# Workflows KT
---
## Why move?
* Current tech stack (Workflow Foundation) no longer supported by Microsoft (since 2017)
* Not .Net Core friendly
* Technical debt making it impossible to make any changes (can't open diagrams in modern version of VS)
* Current code ugly and messy (unless you like spaghetti)
* Lack of testing/tests to capture states/state trnasitions
---
## MassTransit

---
## Sagas
* A saga is a long-lived transaction managed by a coordinator. Sagas are initiated by an event, sagas orchestrate events, and sagas maintain the state of the overall transaction. Sagas are designed to manage the complexity of a distributed transaction without locking and immediate consistency. They manage state and track any compensations required if a partial failure occurs.
---
# Managing state
A state machine defines the states, events, and behavior of a finite state machine. Implemented as a class, which is derived from MassTransitStateMachine<T/>, a state machine is created once, and then used to apply event triggered behavior to state machine instances.
---
## Main components
* StateMachine (defines states, events and transition logic)
* DealEvenState table (where states for workflows are stored)
* Consumers (listen to events, run some code and respond back to state machine)
* Activities (run some code as per definition in state machine)
* Interfaces (definition of events)
---
## Flow
* Deliver the message (event) to StateMachine
* StateMachine will look up the workflow id from `DealEventState` table (CorrelationId)
* StateMachine will move the state (or optionally publish a message ) as per the logic in the `DealEventStateMachine.cs`

---
## Deal Event State Machine (Events and States)
```csharp=
// States
public State Created { get; private set; }
public State AwaitingValidation { get; private set; }
public State AwaitingAction { get; private set; }
public State AwaitingCounterpartyConfirmation { get; private set; }
public State MasterAgreementIncorrect { get; private set; }
public State NoConfirmationRequired { get; private set; }
//... and more
//Events
public Event<CreateWorkflowRequested> CreateRequested { get; private set; }
public Event<WorkflowStatusRequested> StatusRequested { get; private set; }
public Event<AwaitingValidationRequested> AwaitingValidationRequested { get; private set; }
//... and more
```
---
## Events as .NET interfaces
```csharp=
namespace Claws.WorkFlow.MT.Contracts
{
public interface CreateWorkflowRequested
{
Guid WorkflowId { get; }
int DealId { get; }
int BusinessEventId { get; }
int UserId { get; }
string UserCode { get; set; }
string Reference { get; set; }
}
}
```
---
## State Transitions
```csharp=
// AwaitingValidation
During(AwaitingValidation, // state
When(MasterAgreementStatus) // event
.Then(x => { x.Instance.EConfirmationRequired = x.Data.EConfirmationRequired; })
.IfElse(x => x.Data.IsMasterAgreementValid,
isMaValid =>
isMaValid
.SetSystemUser()
.SetMACorrectStatus()
.PublishAsync(x =>
x.Init<CheckDealBrokeredStatus>(new
{
x.Data.WorkflowId,
x.Data.DealId
})),
isMaInvalid =>
isMaInvalid
.TransitionTo(MasterAgreementIncorrect) // new state
.SetSystemUser()
.SetMAIncorrectStatus()
.RespondWorkflowProcessed())
```
---
## DealEventState table
* Holds the state of current workflow

---
## Consumers
```csharp=
public class BuySellStatusCheckerConsumer
: IConsumer<CheckIsDealBuyStatus>
{
// ... code omitted for brevity
public async Task Consume(ConsumeContext<CheckIsDealBuyStatus> context)
{
var workflowId = context.Message.WorkflowId;
var dealId = context.Message.DealId;
try
{
var isBuyDeal = _workflowValidations.IsDealBuy(dealId);
_logger.LogDebug("Publishing [ IsDealBuy ] status [ {Status} ] for deal [{DealId}], workflow [{WorkflowId}]",
isBuyDeal ? "Buy" : "Sell", dealId, workflowId);
await context.RespondAsync<DealBuyStatus>(new
{
DealId = dealId,
IsBuyDeal = isBuyDeal,
WorkflowId = workflowId
});
}
catch (Exception e)
{
await context.RespondAsync<WorkflowStageFaulted>(new
{
StageName = nameof(BuySellStatusCheckerConsumer),
DealId = dealId,
Exception = e,
WorkflowId = workflowId
});
}
}
}
```
---
## Activities
```csharp=
public class SetBrokeredStatusActivity : ActivityBase<DealEventState>
{
public SetBrokeredStatusActivity(IDealManagementFactory dealManagementFactory, IWorkflowStageHelper workflowStageHelper)
: base(dealManagementFactory, workflowStageHelper)
{
}
protected override async Task Execute(BehaviorContext<DealEventState> context)
{
var state = context.Instance;
state.Unmatched = true;
state.NotBrokered = false;
state.CurrentMatchingStatus = WorkflowStates.Unmatched;
var eventMessage = $"DealID {state.DealId} Deal Reference '{state.SourceSystemName}' " +
$"Matching Status moved to '{state.CurrentMatchingStatus}' by {state.UserCode}";
await PostProcess(state, eventMessage);
}
}
```
---
```graphviz
digraph G {
0 [shape=ellipse, label="Initial"];
1 [shape=ellipse, label="Created"];
2 [shape=ellipse, label="AwaitingValidation"];
3 [shape=ellipse, label="DealDeleteReceived"];
4 [shape=ellipse, label="DealEditReceived"];
5 [shape=ellipse, label="Faulted"];
6 [shape=ellipse, label="MasterAgreementIncorrect"];
7 [shape=ellipse, label="NoConfirmationRequired"];
8 [shape=ellipse, label="EConfirmationRequired"];
9 [shape=ellipse, label="AwaitingCounterpartyConfirmation"];
10 [shape=ellipse, label="RequiresConfirmation"];
11 [shape=ellipse, label="AwaitingAction"];
12 [shape=ellipse, label="CounterpartyContractReceived"];
13 [shape=ellipse, label="BrokerDisputed"];
14 [shape=ellipse, label="EndConfirmationState"];
15 [shape=ellipse, label="EConfirmationInProgress"];
16 [shape=ellipse, label="EConfirmationMatched"];
17 [shape=ellipse, label="BPContractGenerated"];
18 [shape=ellipse, label="BPContractSent"];
19 [shape=ellipse, label="Disputed"];
20 [shape=ellipse, label="BPContractConfirmed"];
21 [shape=ellipse, label="BPContractDeemedConfirmed"];
22 [shape=ellipse, label="BPContractResent"];
23 [shape=ellipse, label="BPContractSentToTrader"];
24 [shape=ellipse, label="CounterpartyContractSent"];
25 [shape=rectangle, label="CreateRequested<CreateWorkflowRequested>"];
26 [shape=rectangle, label="AwaitingValidationRequested<AwaitingValidationRequested>"];
27 [shape=rectangle, label="DeleteRequestedEvent<DeleteRequested>"];
28 [shape=rectangle, label="EditRequestedEvent<EditRequested>"];
29 [shape=rectangle, label="WorkflowStageFaulted<WorkflowStageFaulted>"];
30 [shape=rectangle, label="MasterAgreementStatus<MasterAgreementStatus>"];
31 [shape=rectangle, label="DealBrokeredStatus<DealBrokeredStatus>"];
32 [shape=rectangle, label="MasterAgreementRequiresConfirmationStatus<MasterAgreementRequiresConfirmationStatus>"];
33 [shape=rectangle, label="EConfirmationStatusRequested<CheckEConfirmationStatus>"];
34 [shape=rectangle, label="DealBuyStatus<DealBuyStatus>"];
35 [shape=rectangle, label="AwaitingActionRequested<AwaitingActionRequested>"];
36 [shape=rectangle, label="CounterpartyContractReceivedEvent<CounterpartyContractReceived>"];
37 [shape=rectangle, label="RequiresConfirmationRequested<RequiresConfirmationRequested>"];
38 [shape=rectangle, label="BrokerMatchedEvent<BrokerMatched>"];
39 [shape=rectangle, label="BrokerMatchedStatus<IsBrokerMatchedStatus>"];
40 [shape=rectangle, label="EConfirmationInProgressEvent<EConfirmationInProgress>"];
41 [shape=rectangle, label="EConfirmationMatchedEvent<EConfirmationMatched>"];
42 [shape=rectangle, label="BPContractGeneratedEvent<BPContractGenerated>"];
43 [shape=rectangle, label="DisputedEvent<Disputed>"];
44 [shape=rectangle, label="BPContractConfirmedEvent<BPContractConfirmed>"];
45 [shape=rectangle, label="SetIsExceptionBPDeemedConfirmed<SetIsExceptionBPDeemedConfirmed>"];
46 [shape=rectangle, label="ContractDeemedConfirmed<BPContractDeemedConfirmed>"];
47 [shape=rectangle, label="BPContractResentEvent<BPContractResent>"];
48 [shape=rectangle, label="BPContractSentEvent<BPContractSent>"];
49 [shape=rectangle, label="BPContractSentToTraderEvent<BPContractSentToTrader>"];
50 [shape=rectangle, label="CounterpartyContractSentEvent<CounterpartyContractSent>"];
51 [shape=rectangle, label="DeleteAcceptedEvent<HeadingAcceptDeleteRequested>"];
52 [shape=rectangle, label="EditAcceptedEvent<HeadingAcceptEditRequested>"];
0 -> 25;
1 -> 25;
1 -> 26;
1 -> 27;
1 -> 28;
1 -> 29;
2 -> 30;
2 -> 31;
2 -> 32;
2 -> 33;
2 -> 34;
2 -> 35;
2 -> 26;
2 -> 27;
2 -> 28;
2 -> 29;
3 -> 27;
3 -> 51;
3 -> 28;
3 -> 29;
4 -> 27;
4 -> 28;
4 -> 52;
4 -> 29;
5 -> 25;
5 -> 26;
5 -> 27;
5 -> 28;
5 -> 29;
6 -> 35;
6 -> 26;
6 -> 27;
6 -> 28;
6 -> 29;
7 -> 35;
7 -> 26;
7 -> 27;
7 -> 28;
7 -> 39;
7 -> 38;
7 -> 29;
8 -> 40;
8 -> 38;
8 -> 35;
8 -> 26;
8 -> 27;
8 -> 28;
8 -> 29;
9 -> 36;
9 -> 37;
9 -> 38;
9 -> 31;
9 -> 35;
9 -> 26;
9 -> 27;
9 -> 28;
9 -> 29;
10 -> 35;
10 -> 26;
10 -> 27;
10 -> 28;
10 -> 42;
10 -> 38;
10 -> 31;
10 -> 29;
11 -> 35;
11 -> 26;
11 -> 27;
11 -> 28;
11 -> 29;
12 -> 35;
12 -> 26;
12 -> 43;
12 -> 50;
12 -> 38;
12 -> 31;
12 -> 27;
12 -> 28;
12 -> 29;
13 -> 35;
13 -> 26;
13 -> 27;
13 -> 28;
13 -> 29;
14 -> 27;
14 -> 28;
14 -> 26;
14 -> 29;
15 -> 41;
15 -> 38;
15 -> 35;
15 -> 26;
15 -> 27;
15 -> 28;
15 -> 29;
16 -> 31;
16 -> 39;
16 -> 38;
16 -> 35;
16 -> 26;
16 -> 27;
16 -> 28;
16 -> 29;
17 -> 35;
17 -> 26;
17 -> 48;
17 -> 37;
17 -> 38;
17 -> 31;
17 -> 49;
17 -> 27;
17 -> 28;
17 -> 29;
18 -> 35;
18 -> 26;
18 -> 43;
18 -> 44;
18 -> 45;
18 -> 46;
18 -> 38;
18 -> 31;
18 -> 47;
18 -> 37;
18 -> 27;
18 -> 28;
18 -> 29;
19 -> 35;
19 -> 26;
19 -> 27;
19 -> 28;
19 -> 50;
19 -> 44;
19 -> 29;
20 -> 35;
20 -> 26;
20 -> 38;
20 -> 31;
20 -> 39;
20 -> 27;
20 -> 28;
20 -> 29;
21 -> 35;
21 -> 26;
21 -> 43;
21 -> 44;
21 -> 38;
21 -> 31;
21 -> 27;
21 -> 28;
21 -> 29;
22 -> 35;
22 -> 26;
22 -> 43;
22 -> 44;
22 -> 45;
22 -> 46;
22 -> 38;
22 -> 31;
22 -> 27;
22 -> 28;
22 -> 29;
23 -> 35;
23 -> 26;
23 -> 43;
23 -> 44;
23 -> 45;
23 -> 46;
23 -> 38;
23 -> 31;
23 -> 42;
23 -> 27;
23 -> 28;
23 -> 29;
24 -> 35;
24 -> 26;
24 -> 39;
24 -> 38;
24 -> 31;
24 -> 27;
24 -> 28;
24 -> 29;
25 -> 1;
26 -> 2;
27 -> 3;
28 -> 4;
29 -> 5;
30 -> 6;
31 -> 13;
31 -> 14;
32 -> 7;
33 -> 8;
34 -> 9;
34 -> 10;
35 -> 11;
36 -> 12;
37 -> 10;
38 -> 14;
39 -> 14;
40 -> 15;
41 -> 16;
42 -> 17;
43 -> 19;
44 -> 20;
45 -> 21;
46 -> 21;
47 -> 22;
48 -> 18;
49 -> 23;
50 -> 24;
51 -> 14;
52 -> 2;
}
```
## Q's ?
{"metaMigratedAt":"2023-06-16T20:01:27.600Z","metaMigratedFrom":"Content","title":"Workflows KT","breaks":true,"contributors":"[{\"id\":\"c3d77e6f-86ed-47fc-8c64-010aba4c9dd1\",\"add\":14122,\"del\":2451}]"}