workflow-core icon indicating copy to clipboard operation
workflow-core copied to clipboard

How to achieve a better process rollback workflow

Open codecodecookie opened this issue 11 months ago • 4 comments

I use json define workflow like the following picture:

image

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 { context.Item }, "A_NODE") statement or return ExecutionResult.Persist("A_NODE") statement to implements the process of going back from the current process node to A NODE.I konw decision branch can do this ,but I want another way to realize this process. who can give me some advice,ungrateful!

codecodecookie avatar Mar 07 '24 13:03 codecodecookie

Use saga pattern https://workflow-core.readthedocs.io/en/latest/sagas/

brucezlata avatar Apr 16 '24 05:04 brucezlata

@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 avatar Apr 29 '24 04:04 MOwaisfarooq

@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"));

brucezlata avatar May 07 '24 07:05 brucezlata

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();
    }

} ``

MOwaisfarooq avatar May 07 '24 11:05 MOwaisfarooq