workflow-core
workflow-core copied to clipboard
How to terminate a running workflow?
The bug
It appears that IWorkflowController.TerminateWorkflow(string workflowId)
method does not work as one might expect.
If the workflow is running then it returns false and does nothing.
That happens because the implementation first checks if there is a lock associated with the given workflow and if so it immediately returns false
and does nothing.
Since there is always a lock present for a running workflow, effectively it means that we can terminate only non-running workflows which is very unfortunate.
To Reproduce To reproduce the behavior:
- Start a new workflow that would run for a while.
- Try to Terminate or Suspend the workflow.
- Observe that the methods return false and do nothing.
Expected behavior I'd expect that methods succeed and workflow will be terminated once the current step execution is done.
Additional context Any workarounds on how to stop running workflow externally are welcome. Also, I'd be happy to implement the fix if you have a particular design for it, @danielgerlag.
There is a related issue https://github.com/danielgerlag/workflow-core/issues/751 too.
Hello, i'm having the same problem. I'm looking for a workaround, but have found nothing yet
Below is my workaround. Once step fails with retry, I will terminate it and persist workflow. Persistence is a must, otherwise it will be picked up and continue to execute.
var host = app.ApplicationServices.GetService<IWorkflowHost>();
host.OnStepError += (WorkflowInstance workflow, WorkflowStep step, Exception exception) =>
{
try
{
host.TerminateWorkflow(workflow.Id);
host.PersistenceStore.PersistWorkflow(workflow);
}
catch (Exception ex)
{
Logger?.Exception(LoggingEvents.WorkflowStepErrorHandling, ex);
}
};
My workaroun is to just release the lock before calling the workflowcontroller:
await _lockProvider.ReleaseLock(workflowInstanceId);
await _workflowController.TerminateWorkflow(workflowInstanceId);
We could look into creating some kind of scheduled termination, where the workflow will terminate at the end of the current execution cycle if it is locked. In the meantime, a good workaround would be to use a Library like Polly to create a retry policy until it is unlocked... I would strongly recommend NOT to hijack the lock from the executor as suggested by @jjherscheid , this could result in data corruption.
Meanwhile, the approach mentioned here https://github.com/danielgerlag/workflow-core/pull/237 with Parallel
flow and CancelCondition
seems to work, so we can build a workaround to stop workflow from inside.
.Parallel()
.Do(then => then
.StartWith<DoSomething>()
.WaitFor("Approval", (data, context) => context.Workflow.IdNow)
)
.Do(then => then
.StartWith<DoSomething>()
.Delay(data => TimeSpan.FromDays(3))
.Then<EscalateIssue>()
)
.Join()
.CancelCondition(data => data.IsApproved, true)
.Then<MoveAlong>();
I used middleware to do the workaround, first create a step middleware and then check whether user has tried to suspend the workflow and waitforevent like 'Resume' if true. And at this point, the lock is releasted and workflow is suspended, you can now terminate or resume it at your will.