elsa-workflows / elsa-workflows/elsa-core

FlowJoin activity with WaitAny mode not cancel all branches

Open
#6,774 0 comments 0 reactions 0 assignees View on GitHub
triaged
Dominant language
C#
Stars
7.9k
Forks
1.5k
Avg merge
15h 22m
Merged PRs (30d)
114

Description

## Description
When using FlowJoin activity in workflow with WaitAny mode it leads to problems.
One of branches with loop(While activity and Delay inside body of loop) isn't cancelled completely thus, a running activity execution context remains inside the compeleted workflow instance. And this workflow instance cannot view via dashboard, I got error like
``System.Collections.Generic.KeyNotFoundException: The given key '80d8cbe55138aa98' was not present in the dictionary.
at Elsa.Workflows.WorkflowStateExtractor.ApplyActivityExecutionContextsAsync(WorkflowState state, WorkflowExecutionContext workflowExecutionContext)
at Elsa.Workflows.WorkflowStateExtractor.ApplyAsync(WorkflowExecutionContext workflowExecutionContext, WorkflowState state)
at Elsa.Workflows.WorkflowExecutionContext.CreateAsync(IServiceProvider serviceProvider, WorkflowGraph workflowGraph, WorkflowState workflowState, String correlationId, String parentWorkflowInstanceId, IDictionary`2 input, IDictionary`2 properties, ExecuteActivityDelegate executeDelegate, String triggerActivityId, CancellationToken cancellationToken)
at Elsa.Workflows.Management.Services.WorkflowInstanceVariableManager.GetWorkflowExecutionContextAsync(String workflowInstanceId, CancellationToken cancellationToken)
at Elsa.Workflows.Management.Services.WorkflowInstanceVariableManager.GetVariablesAsync(String workflowInstanceId, IEnumerable`1 excludeTags, CancellationToken cancellationToken)``

## Steps to Reproduce
there is the following workflow:
```
{
"id": "Flowchart1",
"type": "Elsa.Flowchart",
"activities": [
{
"id": "WriteLine1",
"type": "Elsa.WriteLine",
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "log 1"
}
}
},
{
"id": "Fork",
"type": "Elsa.FlowFork",
"branches": {
"typeName": "List",
"expression": {
"type": "Object",
"value": "[\"LOOP\",\"NOTLOOP\"]"
}
}
},
{
"id": "WhileLoop",
"type": "Elsa.While",
"condition": {
"typeName": "Boolean",
"expression": {
"type": "Literal",
"value": "true"
}
},
"body": {
"id": "Flowchart3",
"type": "Elsa.Flowchart",
"activities": [
{
"id": "Delay",
"type": "Elsa.Delay",
"timeSpan": {
"typeName": "TimeSpan",
"expression": {
"type": "Literal",
"value": "00:00:10"
}
}
},
{
"id": "IncrementNumber",
"type": "Elsa.SetVariable",
"variable": {
"id": "number",
"name": "Number",
"typeName": "Int32",
"storageDriverTypeName": "Elsa.Workflows.WorkflowInstanceStorageDriver, Elsa.Workflows.Core"
},
"value": {
"typeName": "Int32",
"expression": {
"type": "JavaScript",
"value": "getNumber() + 1"
}
}
},
{
"id": "IfNumber",
"type": "Elsa.If",
"condition": {
"typeName": "Boolean",
"expression": {
"type": "JavaScript",
"value": "getNumber() === 3"
}
},
"then": {
"id": "Break",
"type": "Elsa.Break"
}
}
],
"connections": [
{
"source": "Delay",
"target": "IncrementNumber",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "IncrementNumber",
"target": "IfNumber",
"sourcePort": "Done",
"targetPort": "In"
}
]
}
},
{
"id": "WriteLine2",
"type": "Elsa.WriteLine",
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "log 2"
}
}
},
{
"id": "WriteLine3",
"type": "Elsa.WriteLine",
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "log 3"
}
}
},
{
"id": "Join",
"type": "Elsa.FlowJoin",
"mode": {
"typeName": "Elsa.Workflows.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core",
"expression": {
"type": "Literal",
"value": "WaitAny"
}
}
},
{
"id": "FiFinish",
"type": "Elsa.Finish"
}
],
"connections": [
{
"source": "WriteLine1",
"target": "Fork",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "Fork",
"target": "WhileLoop",
"sourcePort": "LOOP",
"targetPort": "In"
},
{
"source": "Fork",
"target": "WriteLine2",
"sourcePort": "NOTLOOP",
"targetPort": "In"
},
{
"source": "WriteLine2",
"target": "WriteLine3",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WhileLoop",
"target": "Join",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine3",
"target": "Join",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "Join",
"target": "FiFinish",
"sourcePort": "Done",
"targetPort": "In"
}
]
}
```

in this workflow there are two branches(FlowFork and FlowJoin with WaitAny mode).
in one branch some activities, in example above WriteLine2 and WriteLine3 - this branch must complete first.
in second branch of workflow we have loop activity(While) with Flowchart and Delay inside it body - this branch must be cancelled in my scenario.

when I run this workflow, I have 'Completed' workflow instance which passed through the first branch.
but inside instance activityExecutionContexts i see that some activities from second branch in Running status still.
There is comleted workflow instance that I got:
```
{
"id": "2b291a71c414d4c8",
"definitionId": "211726909bfe4d55afac9ade1a05fa93",
"definitionVersionId": "886d49310a52d71f",
"version": 1,
"workflowState": {
"id": "2b291a71c414d4c8",
"definitionId": "211726909bfe4d55afac9ade1a05fa93",
"definitionVersionId": "886d49310a52d71f",
"definitionVersion": 1,
"status": "Finished",
"subStatus": "Finished",
"incidents": [],
"isSystem": false,
"completionCallbacks": [
{
"ownerInstanceId": "6e9582530bcf1655",
"childNodeId": "Workflow1:Flowchart1:WhileLoop:Flowchart3:Delay",
"methodName": "OnChildCompletedAsync"
}
],
"activityExecutionContexts": [
{
"id": "6e9582530bcf1655",
"parentContextId": "80d8cbe55138aa98",
"scheduledActivityNodeId": "Workflow1:Flowchart1:WhileLoop:Flowchart3",
"ownerActivityNodeId": "Workflow1:Flowchart1:WhileLoop",
"properties": {},
"activityState": {},
"dynamicVariables": [],
"status": "Running",
"startedAt": "2025-07-04T11:00:07.037Z"
},
{
"id": "c985a67d8e0bb646",
"scheduledActivityNodeId": "Workflow1",
"properties": {
"Variables": {
"number": {
"options": {
"propertyNameCaseInsensitive": true
}
}
}
},
"activityState": {},
"dynamicVariables": [],
"status": "Completed",
"startedAt": "2025-07-04T11:00:07.029Z",
"completedAt": "2025-07-04T11:00:07.037Z"
}
],
"scheduledActivities": [],
"executionLogSequence": 25,
"input": {},
"output": {},
"properties": {},
"createdAt": "2025-07-04T11:00:07.027Z",
"updatedAt": "2025-07-04T11:00:07.037Z",
"finishedAt": "2025-07-04T11:00:07.037Z"
},
"status": "Finished",
"subStatus": "Finished",
"incidentCount": 0,
"isSystem": false,
"createdAt": "2025-07-04T11:00:07.027Z",
"updatedAt": "2025-07-04T11:00:07.037Z",
"finishedAt": "2025-07-04T11:00:07.037Z"
}
```
there is 'Workflow1:Flowchart1:WhileLoop:Flowchart3' still running in activityExecutionContexts, although judging by the logs I see that this activity tried to cancel.
From logs:
```
...
Receiving signal "ActivityCompleted" on activity "WriteLine2" of type "Elsa.WriteLine"
Receiving signal "ActivityCompleted" on activity "WriteLine3" of type "Elsa.WriteLine"
Receiving signal "ActivityCompleted" on activity "Fork" of type "Elsa.FlowFork"
Receiving signal "ActivityCompleted" on activity "Workflow1" of type "Elsa.Workflow"
Receiving signal "ActivityCompleted" on activity "Flowchart1" of type "Elsa.Flowchart"
Receiving signal "CancelSignal" on activity "Delay" of type "Elsa.Delay"
Receiving signal "CancelSignal" on activity "Flowchart3" of type "Elsa.Flowchart"
Receiving signal "ActivityCompleted" on activity "WhileLoop" of type "Elsa.While"
Receiving signal "CancelSignal" on activity "Workflow1" of type "Elsa.Workflow"
Receiving signal "CancelSignal" on activity "WhileLoop" of type "Elsa.While"
Receiving signal "CancelSignal" on activity "Flowchart3" of type "Elsa.Flowchart"
Receiving signal "ActivityCompleted" on activity "Flowchart3" of type "Elsa.Flowchart"
Receiving signal "ActivityCompleted" on activity "Flowchart1" of type "Elsa.Flowchart"
...
```

so, I cannot view this workflow instance via dashboard because of 'running' activityExecutionContext with "parentContextId": "80d8cbe55138aa98" which not exists in activityExecutionContexts block, I got error:
`System.Collections.Generic.KeyNotFoundException: The given key '80d8cbe55138aa98' was not present in the dictionary.`
from class WorkflowStateExtractor.

This behavior can lead to other problems because of 'running' activity that had to be cancelled

## Expected Behavior
All branches of FlowJoin activity must be completed or cancelled completely, thare are no errors on view workflow instances in dashboard

## Actual Behavior
I cannot view workflow instance in dashboard, activity not cancelled completely

## Environment
- **Elsa Package Version**: 3.4.0

## Additional Context
I saw that refactoring was going on for Join activities, see commit
https://github.com/elsa-workflows/elsa-core/commit/3a1ddb650fe48bbf08f164f269e39e800cb404f8

but this changes not released yet.
do these changes will help? when this changes will be released, so I try to check it?
this problem very blocks our scenarios.

Thank you very much in advance!!!

## Related Issues
https://github.com/elsa-workflows/elsa-core/pull/6592

Contributor guide

Open the contributing guide

Research direction

Reproduce the supplied FlowFork/FlowJoin workflow with WaitAny, including the While, nested Flowchart, and Delay branch. Start by tracing the cancellation logs and inspect WorkflowStateExtractor and the resulting activityExecutionContexts; done means every losing branch is completed or cancelled without an orphaned parentContextId, and the finished instance opens in the dashboard.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.