diff --git a/src/bundles/Elsa.WorkflowServer.Web/Program.cs b/src/bundles/Elsa.WorkflowServer.Web/Program.cs
index d7f8181d3..5d20b3b54 100644
--- a/src/bundles/Elsa.WorkflowServer.Web/Program.cs
+++ b/src/bundles/Elsa.WorkflowServer.Web/Program.cs
@@ -19,7 +19,7 @@ using Proto.Persistence.SqlServer;
const bool useMongoDb = false;
const bool useSqlServer = false;
const bool useDapper = false;
-const bool useProtoActor = true;
+const bool useProtoActor = false;
const bool useHangfire = false;
var builder = WebApplication.CreateBuilder(args);
diff --git a/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowJoin.cs b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowJoin.cs
index c1ab586dc..9023131f6 100644
--- a/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowJoin.cs
+++ b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowJoin.cs
@@ -43,20 +43,24 @@ public class FlowJoin : Activity, IJoinNode
switch (mode)
{
case FlowJoinMode.WaitAll:
+ {
// If all left-inbound activities have executed, complete & continue.
var haveAllInboundActivitiesExecuted = inboundActivities.All(x => flowScope.GetExecutionCount(x) > executionCount);
if (haveAllInboundActivitiesExecuted)
+ {
await context.CompleteActivityAsync();
- break;
- case FlowJoinMode.WaitAny:
- // If this activity was already executed, complete it with the AlreadyCompleted result. This will prevent the Flowchart activity from scheduling its siblings again.
- var alreadyExecuted = inboundActivities.Max(x => flowScope.GetExecutionCount(x)) == executionCount;
- var result = alreadyExecuted ? new AlreadyCompleted() : default;
+ await ClearBookmarksAsync(flowchart, context);
+ }
- await context.CompleteActivityAsync(result);
+ break;
+ }
+ case FlowJoinMode.WaitAny:
+ {
+ await context.CompleteActivityAsync();
await ClearBookmarksAsync(flowchart, context);
break;
+ }
}
}
diff --git a/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/Flowchart.cs b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/Flowchart.cs
index 48c9b7795..f404e9d06 100644
--- a/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/Flowchart.cs
+++ b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/Flowchart.cs
@@ -6,6 +6,7 @@ using Elsa.Workflows.Core.Activities.Flowchart.Extensions;
using Elsa.Workflows.Core.Activities.Flowchart.Models;
using Elsa.Workflows.Core.Attributes;
using Elsa.Workflows.Core.Contracts;
+using Elsa.Workflows.Core.Options;
using Elsa.Workflows.Core.Signals;
namespace Elsa.Workflows.Core.Activities.Flowchart.Activities;
@@ -202,7 +203,15 @@ public class Flowchart : Container
}
else
{
- await flowchartContext.ScheduleActivityAsync(activity, OnChildCompletedAsync);
+ // Select an existing activity execution context for this activity, if any.
+ var joinContext = flowchartContext.WorkflowExecutionContext.ActiveActivityExecutionContexts.FirstOrDefault(x => x.ParentActivityExecutionContext == flowchartContext && x.Activity == activity);
+ var scheduleWorkOptions = new ScheduleWorkOptions
+ {
+ CompletionCallback = OnChildCompletedAsync,
+ ReuseActivityExecutionContextId = joinContext?.Id,
+ PreventDuplicateScheduling = true
+ };
+ await flowchartContext.ScheduleActivityAsync(activity, scheduleWorkOptions);
}
}
}
diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IActivityScheduler.cs b/src/modules/Elsa.Workflows.Core/Contracts/IActivityScheduler.cs
index 7ad3d9f6c..794177cf0 100644
--- a/src/modules/Elsa.Workflows.Core/Contracts/IActivityScheduler.cs
+++ b/src/modules/Elsa.Workflows.Core/Contracts/IActivityScheduler.cs
@@ -16,21 +16,25 @@ public interface IActivityScheduler
///
/// Schedules a work item.
///
- ///
+ /// The work item to schedule.
void Schedule(ActivityWorkItem workItem);
///
/// Takes the next work item from the scheduler.
///
- ///
ActivityWorkItem Take();
///
/// Returns a list of all work items in the scheduler.
///
- ///
IEnumerable List();
+ ///
+ /// Returns true if there are any work items matching the specified predicate.
+ ///
+ /// The predicate to match.
+ bool Any(Func predicate);
+
///
/// Clears all work items from the scheduler.
///
diff --git a/src/modules/Elsa.Workflows.Core/Extensions/WorkflowExecutionContextExtensions.cs b/src/modules/Elsa.Workflows.Core/Extensions/WorkflowExecutionContextExtensions.cs
index 600af62a0..e25afabc6 100644
--- a/src/modules/Elsa.Workflows.Core/Extensions/WorkflowExecutionContextExtensions.cs
+++ b/src/modules/Elsa.Workflows.Core/Extensions/WorkflowExecutionContextExtensions.cs
@@ -87,15 +87,22 @@ public static class WorkflowExecutionContextExtensions
ActivityExecutionContext owner,
ScheduleWorkOptions? options = default)
{
+ var scheduler = workflowExecutionContext.Scheduler;
+
+ if(options?.PreventDuplicateScheduling == true && scheduler.Any(x => x.ActivityId == activityNode.NodeId))
+ return;
+
var activityInvoker = workflowExecutionContext.GetRequiredService();
var toolVersion = workflowExecutionContext.Workflow.WorkflowMetadata.ToolVersion;
var activityId = toolVersion?.Major >= 3 ? activityNode.Activity.Id : activityNode.NodeId;
var tag = options?.Tag;
- var activityInvocationOptions = new ActivityInvocationOptions(owner, tag, options?.Variables);
+ var activityInvocationOptions = new ActivityInvocationOptions(owner, tag, options?.Variables, options?.ReuseActivityExecutionContextId);
var workItem = new ActivityWorkItem(activityId, owner.Id, async () => await activityInvoker.InvokeAsync(workflowExecutionContext, activityNode.Activity, activityInvocationOptions), tag);
var completionCallback = options?.CompletionCallback;
- workflowExecutionContext.Scheduler.Schedule(workItem);
+
workflowExecutionContext.AddCompletionCallback(owner, activityNode, completionCallback, tag);
+ scheduler.Schedule(workItem);
+
}
///
diff --git a/src/modules/Elsa.Workflows.Core/Options/ActivityInvocationOptions.cs b/src/modules/Elsa.Workflows.Core/Options/ActivityInvocationOptions.cs
index 1fbb3479a..e78be270f 100644
--- a/src/modules/Elsa.Workflows.Core/Options/ActivityInvocationOptions.cs
+++ b/src/modules/Elsa.Workflows.Core/Options/ActivityInvocationOptions.cs
@@ -8,4 +8,4 @@ namespace Elsa.Workflows.Core.Options;
/// The activity execution context that owns this invocation.
/// An optional tag that can be used to identify the invocation.
/// The variables to declare in the activity execution context that will be created for this invocation.
-public record ActivityInvocationOptions(ActivityExecutionContext? Owner, object? Tag, IEnumerable? Variables);
\ No newline at end of file
+public record ActivityInvocationOptions(ActivityExecutionContext? Owner, object? Tag, IEnumerable? Variables, string? ReuseActivityExecutionContextId = default);
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Options/ScheduleWorkOptions.cs b/src/modules/Elsa.Workflows.Core/Options/ScheduleWorkOptions.cs
index b21795cda..8cdf3cf99 100644
--- a/src/modules/Elsa.Workflows.Core/Options/ScheduleWorkOptions.cs
+++ b/src/modules/Elsa.Workflows.Core/Options/ScheduleWorkOptions.cs
@@ -9,4 +9,9 @@ namespace Elsa.Workflows.Core.Options;
/// The callback to invoke when the work item has completed.
/// A tag that can be used to identify the work item.
/// A collection of variables to declare in the activity execution context that will be created for this work item.
-public record ScheduleWorkOptions(ActivityCompletionCallback? CompletionCallback = default, object? Tag = default, ICollection? Variables = default);
\ No newline at end of file
+public record ScheduleWorkOptions(
+ ActivityCompletionCallback? CompletionCallback = default,
+ object? Tag = default,
+ ICollection? Variables = default,
+ string? ReuseActivityExecutionContextId = default,
+ bool PreventDuplicateScheduling = false);
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Services/ActivityInvoker.cs b/src/modules/Elsa.Workflows.Core/Services/ActivityInvoker.cs
index b6d4347bc..134347db8 100644
--- a/src/modules/Elsa.Workflows.Core/Services/ActivityInvoker.cs
+++ b/src/modules/Elsa.Workflows.Core/Services/ActivityInvoker.cs
@@ -19,11 +19,21 @@ public class ActivityInvoker : IActivityInvoker
///
public async Task InvokeAsync(WorkflowExecutionContext workflowExecutionContext, IActivity activity, ActivityInvocationOptions? options = default)
{
- // Setup an activity execution context.
- var activityExecutionContext = workflowExecutionContext.CreateActivityExecutionContext(activity, options);
+ // Setup an activity execution context, potentially reusing an existing one if requested.
+ var reuseActivityExecutionContextId = options?.ReuseActivityExecutionContextId;
- // Add the activity context to the workflow context.
- workflowExecutionContext.AddActivityExecutionContext(activityExecutionContext);
+ var activityExecutionContext = reuseActivityExecutionContextId != null
+ ? workflowExecutionContext.ActiveActivityExecutionContexts.FirstOrDefault(x => x.Id == reuseActivityExecutionContextId)
+ : default;
+
+ if (activityExecutionContext == null)
+ {
+ // Create a new activity execution context.
+ activityExecutionContext = workflowExecutionContext.CreateActivityExecutionContext(activity, options);
+
+ // Add the activity context to the workflow context.
+ workflowExecutionContext.AddActivityExecutionContext(activityExecutionContext);
+ }
// Execute the activity execution pipeline.
await InvokeAsync(activityExecutionContext);
diff --git a/src/modules/Elsa.Workflows.Core/Services/QueueBasedActivityScheduler.cs b/src/modules/Elsa.Workflows.Core/Services/QueueBasedActivityScheduler.cs
index d68611e17..26e8c28e1 100644
--- a/src/modules/Elsa.Workflows.Core/Services/QueueBasedActivityScheduler.cs
+++ b/src/modules/Elsa.Workflows.Core/Services/QueueBasedActivityScheduler.cs
@@ -24,6 +24,9 @@ public class QueueBasedActivityScheduler : IActivityScheduler
///
public IEnumerable List() => _queue.ToList();
+ ///
+ public bool Any(Func predicate) => _queue.Any(predicate);
+
///
public void Clear() => _queue.Clear();
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Services/StackBasedActivityScheduler.cs b/src/modules/Elsa.Workflows.Core/Services/StackBasedActivityScheduler.cs
index ec8d92adf..dda6d7fb1 100644
--- a/src/modules/Elsa.Workflows.Core/Services/StackBasedActivityScheduler.cs
+++ b/src/modules/Elsa.Workflows.Core/Services/StackBasedActivityScheduler.cs
@@ -24,6 +24,9 @@ public class StackBasedActivityScheduler : IActivityScheduler
///
public IEnumerable List() => _stack.ToList();
+ ///
+ public bool Any(Func predicate) => _stack.Any(predicate);
+
///
public void Clear() => _stack.Clear();
}
\ No newline at end of file
diff --git a/test/integration/Elsa.IntegrationTests/Elsa.IntegrationTests.csproj b/test/integration/Elsa.IntegrationTests/Elsa.IntegrationTests.csproj
index 600d87b1d..63b2fe16c 100644
--- a/test/integration/Elsa.IntegrationTests/Elsa.IntegrationTests.csproj
+++ b/test/integration/Elsa.IntegrationTests/Elsa.IntegrationTests.csproj
@@ -96,12 +96,18 @@
Always
-
+
Always
Always
+
+ Always
+
+
+ Always
+
diff --git a/test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/ExplicitJoinWaitAnyTests.cs b/test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/ExplicitJoinWaitAnyTests.cs
index 06e944b05..17f2754f2 100644
--- a/test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/ExplicitJoinWaitAnyTests.cs
+++ b/test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/ExplicitJoinWaitAnyTests.cs
@@ -18,14 +18,17 @@ public class ExplicitJoinWaitAnyTests
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
}
- [Fact(DisplayName = "Workflows with explicit joins using WaitAny wait for any of the specified activities to complete and complete the workflow.")]
- public async Task Test1()
+ [Theory(DisplayName = "Workflows with explicit joins complete the workflow.")]
+ [InlineData("join-any-1.json", "Start; End")]
+ [InlineData("join-all-1.json", "Start; Line 1; Line 2; End")]
+ [InlineData("join-all-2.json", "Start; Line 1; Line 2; End")]
+ public async Task Test1(string workflowFileName, string expectedLines)
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Import workflow.
- var fileName = "Scenarios/ExplicitJoins/Workflows/flow-join-any.json";
+ var fileName = $"Scenarios/ExplicitJoins/Workflows/{workflowFileName}";
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync(fileName);
// Execute.
@@ -33,7 +36,8 @@ public class ExplicitJoinWaitAnyTests
// Assert expected output.
var lines = _capturingTextWriter.Lines.ToList();
- Assert.Equal(new[] { "Start", "End" }, lines);
+ var expectedLinesArray = expectedLines.Split(";", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList();
+ Assert.Equal(expectedLinesArray, lines);
// Assert expected workflow status.
Assert.Equal(WorkflowStatus.Finished, workflowState.Status);
diff --git a/test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/Workflows/join-all-1.json b/test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/Workflows/join-all-1.json
new file mode 100644
index 000000000..fd1fb2847
--- /dev/null
+++ b/test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/Workflows/join-all-1.json
@@ -0,0 +1 @@
+{"id":"9948e541b0e540c384c6eb9fdcf1d544","definitionId":"296428cc22bd4f309e858f4b461dbb3d","name":"Join 1","createdAt":"2023-09-12T18:12:54.370149+00:00","version":2,"toolVersion":"3.0.0.0","variables":[],"inputs":[],"outputs":[],"outcomes":[],"customProperties":{},"isReadonly":false,"isLatest":true,"isPublished":true,"options":{"autoUpdateConsumingWorkflows":false},"root":{"type":"Elsa.Flowchart","version":1,"id":"sL581qWiIEOpRncv5Ez33A","metadata":{},"customProperties":{"source":"FlowchartJsonConverter.cs:46","notFoundConnections":[],"canStartWorkflow":false,"runAsynchronously":false},"activities":[{"mode":{"typeName":"Elsa.Workflows.Core.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core","expression":{"type":"Literal","value":"WaitAll"},"memoryReference":{"id":"aA4pfJOzyEqmLOY3U3vCoQ:input-0"}},"id":"aA4pfJOzyEqmLOY3U3vCoQ","name":"FlowJoin1","type":"Elsa.FlowJoin","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":198,"y":-266},"size":{"width":136.859375,"height":50}}}},{"text":{"typeName":"String","expression":{"type":"Literal","value":"Start"},"memoryReference":{"id":"FRXh0PlHekejZiWANAplUg:input-0"}},"id":"FRXh0PlHekejZiWANAplUg","name":"WriteLine1","type":"Elsa.WriteLine","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":-287,"y":-266},"size":{"width":102.21875,"height":50}},"displayText":"Start"}},{"text":{"typeName":"String","expression":{"type":"Literal","value":"Line 1"},"memoryReference":{"id":"GaVrCWqBDkS6YrvydxKvFA:input-0"}},"id":"GaVrCWqBDkS6YrvydxKvFA","name":"WriteLine2","type":"Elsa.WriteLine","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":-40,"y":-316},"size":{"width":110.65625,"height":50}},"displayText":"Line 1"}},{"text":{"typeName":"String","expression":{"type":"Literal","value":"Line 2"},"memoryReference":{"id":"9Z7bt98j00uRMt9TS2FD0g:input-0"}},"id":"9Z7bt98j00uRMt9TS2FD0g","name":"WriteLine3","type":"Elsa.WriteLine","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":-40,"y":-207},"size":{"width":110.65625,"height":50}},"displayText":"Line 2"}},{"text":{"typeName":"String","expression":{"type":"Literal","value":"End"},"memoryReference":{"id":"MplDrS_bUE-8td-XBUvWmA:input-0"}},"id":"MplDrS_bUE-8td-XBUvWmA","name":"WriteLine4","type":"Elsa.WriteLine","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":430,"y":-266},"size":{"width":139.296875,"height":50}}}}],"connections":[{"source":{"activity":"FRXh0PlHekejZiWANAplUg","port":"Done"},"target":{"activity":"GaVrCWqBDkS6YrvydxKvFA","port":"In"}},{"source":{"activity":"FRXh0PlHekejZiWANAplUg","port":"Done"},"target":{"activity":"9Z7bt98j00uRMt9TS2FD0g","port":"In"}},{"source":{"activity":"9Z7bt98j00uRMt9TS2FD0g","port":"Done"},"target":{"activity":"aA4pfJOzyEqmLOY3U3vCoQ","port":"In"}},{"source":{"activity":"GaVrCWqBDkS6YrvydxKvFA","port":"Done"},"target":{"activity":"aA4pfJOzyEqmLOY3U3vCoQ","port":"In"}},{"source":{"activity":"aA4pfJOzyEqmLOY3U3vCoQ","port":"Done"},"target":{"activity":"MplDrS_bUE-8td-XBUvWmA","port":"In"}}]}}
\ No newline at end of file
diff --git a/test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/Workflows/join-all-2.json b/test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/Workflows/join-all-2.json
new file mode 100644
index 000000000..de848a14d
--- /dev/null
+++ b/test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/Workflows/join-all-2.json
@@ -0,0 +1 @@
+{"id":"14984c048db34cceaf5e15ece80f9703","definitionId":"64f8f2c852f04dc28f60707034d7a906","name":"Join 2","createdAt":"2023-09-12T18:12:43.392272+00:00","version":1,"toolVersion":"3.0.0.0","variables":[],"inputs":[],"outputs":[],"outcomes":[],"customProperties":{},"isReadonly":false,"isLatest":true,"isPublished":true,"options":{"autoUpdateConsumingWorkflows":false},"root":{"type":"Elsa.Flowchart","version":1,"id":"B2jpPDriPEe-zSOhVuAGeQ","metadata":{},"customProperties":{"source":"FlowchartJsonConverter.cs:46","notFoundConnections":[],"canStartWorkflow":false,"runAsynchronously":false},"activities":[{"text":{"typeName":"String","expression":{"type":"Literal","value":"Start"},"memoryReference":{"id":"2yPLgUudQEGPaschdLdkGg:input-0"}},"id":"2yPLgUudQEGPaschdLdkGg","name":"WriteLine1","type":"Elsa.WriteLine","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":-358.5,"y":-229},"size":{"width":139.296875,"height":50}},"displayText":"Start"}},{"body":{"type":"Elsa.Flowchart","version":1,"id":"zaAIlUtQDEaPqeITeRJ4_w","metadata":{},"customProperties":{"source":"FlowchartJsonConverter.cs:46","notFoundConnections":[],"canStartWorkflow":false,"runAsynchronously":false},"activities":[{"text":{"typeName":"String","expression":{"type":"Literal","value":"Line 2"},"memoryReference":{"id":"g3jVTdvU3EK7V5JqRqfqjQ:input-0"}},"id":"g3jVTdvU3EK7V5JqRqfqjQ","name":"WriteLine1","type":"Elsa.WriteLine","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":-279.5,"y":-294},"size":{"width":139.296875,"height":50}},"displayText":"Line 2"}}],"connections":[]},"id":"eHAEEQ-Iu0GwM3mRxZin0Q","name":"FlowNode1","type":"Elsa.FlowNode","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":-120,"y":-179},"size":{"width":211.15625,"height":120}},"displayText":"Line 2"}},{"text":{"typeName":"String","expression":{"type":"Literal","value":"Line 1"},"memoryReference":{"id":"7RQ2sbVHo0SxsyK0dvTKEA:input-0"}},"id":"7RQ2sbVHo0SxsyK0dvTKEA","name":"WriteLine2","type":"Elsa.WriteLine","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":-120,"y":-279},"size":{"width":139.296875,"height":50}},"displayText":"Line 1"}},{"mode":{"typeName":"Elsa.Workflows.Core.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core","expression":{"type":"Literal","value":"WaitAll"},"memoryReference":{"id":"dVUuwMm5XUiYpiYoGo5JKA:input-0"}},"id":"dVUuwMm5XUiYpiYoGo5JKA","name":"FlowJoin1","type":"Elsa.FlowJoin","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":180.5,"y":-229},"size":{"width":136.859375,"height":50}}}},{"text":{"typeName":"String","expression":{"type":"Literal","value":"End"},"memoryReference":{"id":"NpZ_yT_irUuE9ASEfYLxbw:input-0"}},"id":"NpZ_yT_irUuE9ASEfYLxbw","name":"WriteLine3","type":"Elsa.WriteLine","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":400,"y":-229},"size":{"width":139.296875,"height":50}},"displayText":"End"}}],"connections":[{"source":{"activity":"2yPLgUudQEGPaschdLdkGg","port":"Done"},"target":{"activity":"7RQ2sbVHo0SxsyK0dvTKEA","port":"In"}},{"source":{"activity":"2yPLgUudQEGPaschdLdkGg","port":"Done"},"target":{"activity":"eHAEEQ-Iu0GwM3mRxZin0Q","port":"In"}},{"source":{"activity":"7RQ2sbVHo0SxsyK0dvTKEA","port":"Done"},"target":{"activity":"dVUuwMm5XUiYpiYoGo5JKA","port":"In"}},{"source":{"activity":"eHAEEQ-Iu0GwM3mRxZin0Q","port":"Done"},"target":{"activity":"dVUuwMm5XUiYpiYoGo5JKA","port":"In"}},{"source":{"activity":"dVUuwMm5XUiYpiYoGo5JKA","port":"Done"},"target":{"activity":"NpZ_yT_irUuE9ASEfYLxbw","port":"In"}}]}}
\ No newline at end of file
diff --git a/test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/Workflows/flow-join-any.json b/test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/Workflows/join-any-1.json
similarity index 100%
rename from test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/Workflows/flow-join-any.json
rename to test/integration/Elsa.IntegrationTests/Scenarios/ExplicitJoins/Workflows/join-any-1.json