workflow-core
workflow-core copied to clipboard
How to achieve a better process rollback workflow
I use json define workflow like the following picture:
but when the steps nodes become more and more,the decision branch may not be a good solution.I have tyied with this funciton: At the StepType corresponding method in Run(),use return ExecutionResult.Branch(new List
Use saga pattern https://workflow-core.readthedocs.io/en/latest/sagas/
@brucezlata Can you please let me know how I can implement saga transaction. I am using EventPublish to forward the workflow step and in each step i have perform some database transaction through service injection. if error raises on any step, it will suspend the workflow and rollback my service transaction for current step only.
@MOwaisfarooq you can check the above link, for example, throw exception once there is any error in any of your steps (Tasks), then, compensate entire saga transaction (UndoEverything).
builder
.StartWith(context => Console.WriteLine("Begin"))
.Saga(saga => saga
.StartWith<Task1>()
.Then<Task2>()
.Then<Task3>()
)
.CompensateWith<**UndoEverything**>()
.Then(context => Console.WriteLine("End"));
If an error occurs in step B of the workflow, I suspend the workflow to publish this event later from the controller API. The _workflowStepDetailsService.UpdateTransactionForStepB has made a transaction in my table stepTable. I want to revert only the step B service transaction that updated the table. I don't want to undo everything, so that next time I can continue from step B after the error. For example, if I made an insertion in step A using _workflowStepDetailsService.CreateTransactionforStepA in my stepTable, I want to preserve that transaction and only undo the changes made by step B.
builder .StartWith(context => Console.WriteLine("Begin")) .UseDefaultErrorBehavior(WorkflowErrorHandling.Suspend) .Saga(saga => saga .StartWith<stepA>() .Then<stepB>() .Then<stepC>() ) .CompensateWith<**UndoEverything**>() .Then(context => Console.WriteLine("End"));
``
public class stepA: StepBodyAsync
{
private readonly IWorkflowStepDetailsService _workflowStepDetailsService;
public stepA(IWorkflowStepDetailsService workflowStepDetailsService)
{
_workflowStepDetailsService = workflowStepDetailsService;
}
public override async Task<ExecutionResult> RunAsync(IStepExecutionContext context)
{
if (!context.ExecutionPointer.EventPublished)
{
return ExecutionResult.WaitForEvent("StartWorkflowEvent", context.Workflow.Id, DateTime.Now);
}
var workflowsteprequest = (WorkFlowStepDetails)context.ExecutionPointer.EventData;
await _workflowStepDetailsService.CreateTransactionforStepA(workflowsteprequest);
return ExecutionResult.Next();
}
}
`` public class stepB : StepBodyAsync { private readonly IWorkflowStepDetailsService _workflowStepDetailsService;
public stepB: (IWorkflowStepDetailsService workflowStepDetailsService)
{
_workflowStepDetailsService = workflowStepDetailsService;
}
public override async Task<ExecutionResult> RunAsync(IStepExecutionContext context)
{
if (!context.ExecutionPointer.EventPublished)
{
return ExecutionResult.WaitForEvent("StartWorkflowEvent", context.Workflow.Id, DateTime.Now);
}
var workflowsteprequest = (WorkFlowStepDetails)context.ExecutionPointer.EventData;
await _workflowStepDetailsService.UpdateTransactionForStepB(workflowsteprequest);
return ExecutionResult.Next();
}
} ``