diff --git a/src/apps/Elsa.Server.Web/Elsa.Server.Web.csproj b/src/apps/Elsa.Server.Web/Elsa.Server.Web.csproj
index c0537447d..6fa3939e8 100644
--- a/src/apps/Elsa.Server.Web/Elsa.Server.Web.csproj
+++ b/src/apps/Elsa.Server.Web/Elsa.Server.Web.csproj
@@ -7,6 +7,7 @@
+
diff --git a/src/apps/Elsa.Server.Web/Program.cs b/src/apps/Elsa.Server.Web/Program.cs
index 69e723bbb..71ef18012 100644
--- a/src/apps/Elsa.Server.Web/Program.cs
+++ b/src/apps/Elsa.Server.Web/Program.cs
@@ -17,6 +17,7 @@ using Elsa.Workflows.CommitStates.Strategies;
using Elsa.Workflows.IncidentStrategies;
using Elsa.Workflows.LogPersistence;
using Elsa.Workflows.Options;
+using Elsa.Workflows.Runtime.Distributed.Extensions;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Tasks;
using JetBrains.Annotations;
@@ -70,6 +71,7 @@ services
{
runtime.UseEntityFrameworkCore(ef => ef.UseSqlite());
runtime.UseCache();
+ runtime.UseDistributedRuntime();
})
.UseWorkflowsApi()
.UseScheduling()
diff --git a/src/apps/Elsa.Server.Web/appsettings.json b/src/apps/Elsa.Server.Web/appsettings.json
index b0bd725e6..f7456f2df 100644
--- a/src/apps/Elsa.Server.Web/appsettings.json
+++ b/src/apps/Elsa.Server.Web/appsettings.json
@@ -2,7 +2,8 @@
"Logging": {
"LogLevel": {
"Default": "Warning",
- "Microsoft.Hosting.Lifetime": "Information"
+ "Microsoft.Hosting.Lifetime": "Information",
+ "Elsa": "Debug"
}
},
"HostBuilder": {
diff --git a/src/common/Elsa.Testing.Shared.Component/Activities/TriggerSignal.cs b/src/common/Elsa.Testing.Shared.Component/Activities/TriggerSignal.cs
index 78fd7c47c..e3e9b3ca9 100644
--- a/src/common/Elsa.Testing.Shared.Component/Activities/TriggerSignal.cs
+++ b/src/common/Elsa.Testing.Shared.Component/Activities/TriggerSignal.cs
@@ -4,9 +4,9 @@ using Elsa.Workflows.Runtime;
namespace Elsa.Testing.Shared.Activities;
-public class TriggerSignal(object signal) : CodeActivity
+public class TriggerSignal(string signal) : CodeActivity
{
- public object Signal { get; set; } = signal;
+ public string Signal { get; set; } = signal;
protected override void Execute(ActivityExecutionContext context)
{
diff --git a/test/component/Elsa.Workflows.ComponentTests/Helpers/Models/TestWorkflowExecutionResult.cs b/src/common/Elsa.Testing.Shared.Component/Models/TestWorkflowExecutionResult.cs
similarity index 90%
rename from test/component/Elsa.Workflows.ComponentTests/Helpers/Models/TestWorkflowExecutionResult.cs
rename to src/common/Elsa.Testing.Shared.Component/Models/TestWorkflowExecutionResult.cs
index 5db0f9ef8..12ccb0f33 100644
--- a/test/component/Elsa.Workflows.ComponentTests/Helpers/Models/TestWorkflowExecutionResult.cs
+++ b/src/common/Elsa.Testing.Shared.Component/Models/TestWorkflowExecutionResult.cs
@@ -1,6 +1,7 @@
+using Elsa.Workflows;
using Elsa.Workflows.Runtime.Entities;
-namespace Elsa.Workflows.ComponentTests.Models;
+namespace Elsa.Testing.Shared.Models;
///
/// Represents the result of a test workflow execution, including the workflow execution context and activity execution records.
diff --git a/test/component/Elsa.Workflows.ComponentTests/Helpers/Services/AsyncWorkflowRunner.cs b/src/common/Elsa.Testing.Shared.Component/Services/AsyncWorkflowRunner.cs
similarity index 95%
rename from test/component/Elsa.Workflows.ComponentTests/Helpers/Services/AsyncWorkflowRunner.cs
rename to src/common/Elsa.Testing.Shared.Component/Services/AsyncWorkflowRunner.cs
index 8fb09b3a7..39f79c2b6 100644
--- a/test/component/Elsa.Workflows.ComponentTests/Helpers/Services/AsyncWorkflowRunner.cs
+++ b/src/common/Elsa.Testing.Shared.Component/Services/AsyncWorkflowRunner.cs
@@ -1,13 +1,12 @@
-using Elsa.Testing.Shared;
-using Elsa.Testing.Shared.Services;
-using Elsa.Workflows.ComponentTests.Models;
+using System.Collections.Concurrent;
+using Elsa.Testing.Shared.Models;
+using Elsa.Workflows;
using Elsa.Workflows.Models;
using Elsa.Workflows.Runtime;
using Elsa.Workflows.Runtime.Entities;
using Elsa.Workflows.Runtime.Messages;
-using System.Collections.Concurrent;
-namespace Elsa.Workflows.ComponentTests.Services;
+namespace Elsa.Testing.Shared.Services;
///
/// Provides functionality to execute workflows asynchronously and await their completion for testing purposes.
diff --git a/src/modules/Elsa.Workflows.Management/Contracts/IWorkflowInstanceVariableManager.cs b/src/modules/Elsa.Workflows.Management/Contracts/IWorkflowInstanceVariableManager.cs
index 440288489..b1ad89ecd 100644
--- a/src/modules/Elsa.Workflows.Management/Contracts/IWorkflowInstanceVariableManager.cs
+++ b/src/modules/Elsa.Workflows.Management/Contracts/IWorkflowInstanceVariableManager.cs
@@ -1,5 +1,11 @@
+using Elsa.Workflows.Management.Entities;
+using Elsa.Workflows.State;
+
namespace Elsa.Workflows.Management;
+///
+/// Defines the operations for managing variables associated with a workflow instance.
+///
public interface IWorkflowInstanceVariableManager
{
///
@@ -8,8 +14,26 @@ public interface IWorkflowInstanceVariableManager
/// The ID of the workflow instance.
///
/// The cancellation token to cancel the operation.
- /// A task that represents the asynchronous operation. The task result contains a collection of instances.
- Task> GetVariablesAsync(string workflowInstanceId, IEnumerable? excludeTags = default, CancellationToken cancellationToken = default);
+ /// A collection of instances.
+ Task> GetVariablesAsync(string workflowInstanceId, IEnumerable? excludeTags = null, CancellationToken cancellationToken = default);
+
+ ///
+ /// Retrieves all variables for the specified workflow instance.
+ ///
+ /// The workflow instance from which to retrieve variables.
+ /// A collection of tags to exclude from the variable results, if any.
+ /// The cancellation token to cancel the operation.
+ /// A collection of instances.
+ Task> GetVariablesAsync(WorkflowInstance workflowInstance, IEnumerable? excludeTags = null, CancellationToken cancellationToken = default);
+
+ ///
+ /// Retrieves all variables for the specified workflow state.
+ ///
+ /// The workflow state to retrieve variables from.
+ /// Optional tags to exclude from the result.
+ /// The cancellation token to cancel the operation.
+ /// A collection of instances.
+ Task> GetVariablesAsync(WorkflowState workflowState, IEnumerable? excludeTags = null, CancellationToken cancellationToken = default);
///
/// Retrieves all variables from the specified .
@@ -17,8 +41,8 @@ public interface IWorkflowInstanceVariableManager
/// The context of the workflow execution.
///
/// The cancellation token to cancel the operation.
- /// A task that represents the asynchronous operation. The task result contains a collection of instances.
- Task> GetVariablesAsync(WorkflowExecutionContext workflowExecutionContext, IEnumerable? excludeTags = default, CancellationToken cancellationToken = default);
+ /// A collection of instances.
+ Task> GetVariablesAsync(WorkflowExecutionContext workflowExecutionContext, IEnumerable? excludeTags = null, CancellationToken cancellationToken = default);
///
/// Sets the specified variables in the specified workflow instance.
diff --git a/src/modules/Elsa.Workflows.Management/Services/WorkflowInstanceVariableManager.cs b/src/modules/Elsa.Workflows.Management/Services/WorkflowInstanceVariableManager.cs
index 69fb2fb27..23552c877 100644
--- a/src/modules/Elsa.Workflows.Management/Services/WorkflowInstanceVariableManager.cs
+++ b/src/modules/Elsa.Workflows.Management/Services/WorkflowInstanceVariableManager.cs
@@ -1,24 +1,39 @@
+using Elsa.Workflows.Management.Entities;
+using Elsa.Workflows.State;
+
namespace Elsa.Workflows.Management.Services;
public class WorkflowInstanceVariableManager(
- IWorkflowInstanceManager workflowInstanceManager,
- IWorkflowDefinitionService workflowDefinitionService,
- IServiceProvider serviceProvider,
+ IWorkflowInstanceManager workflowInstanceManager,
+ IWorkflowDefinitionService workflowDefinitionService,
+ IServiceProvider serviceProvider,
IWorkflowInstanceVariableReader variableReader,
IWorkflowInstanceVariableWriter variableWriter) : IWorkflowInstanceVariableManager
{
- public async Task> GetVariablesAsync(string workflowInstanceId, IEnumerable? excludeTags = default, CancellationToken cancellationToken = default)
+ public async Task> GetVariablesAsync(string workflowInstanceId, IEnumerable? excludeTags = null, CancellationToken cancellationToken = default)
{
var workflowExecutionContext = await GetWorkflowExecutionContextAsync(workflowInstanceId, cancellationToken);
if (workflowExecutionContext == null) return [];
return await variableReader.GetVariables(workflowExecutionContext, excludeTags, cancellationToken);
}
- public Task> GetVariablesAsync(WorkflowExecutionContext workflowExecutionContext, IEnumerable? excludeTags = default, CancellationToken cancellationToken = default)
+ public Task> GetVariablesAsync(WorkflowExecutionContext workflowExecutionContext, IEnumerable? excludeTags = null, CancellationToken cancellationToken = default)
{
return variableReader.GetVariables(workflowExecutionContext, excludeTags, cancellationToken);
}
+ public async Task> GetVariablesAsync(WorkflowInstance workflowInstance, IEnumerable? excludeTags = null, CancellationToken cancellationToken = default)
+ {
+ return await GetVariablesAsync(workflowInstance.WorkflowState, excludeTags, cancellationToken);
+ }
+
+ public async Task> GetVariablesAsync(WorkflowState workflowState, IEnumerable? excludeTags = null, CancellationToken cancellationToken = default)
+ {
+ var workflowExecutionContext = await GetWorkflowExecutionContextAsync(workflowState, cancellationToken);
+ if (workflowExecutionContext == null) return [];
+ return await variableReader.GetVariables(workflowExecutionContext, excludeTags, cancellationToken);
+ }
+
public async Task> SetVariablesAsync(string workflowInstanceId, IEnumerable variables, CancellationToken cancellationToken = default)
{
var workflowExecutionContext = await GetWorkflowExecutionContextAsync(workflowInstanceId, cancellationToken);
@@ -32,20 +47,26 @@ public class WorkflowInstanceVariableManager(
{
return variableWriter.SetVariables(workflowExecutionContext, variables, cancellationToken);
}
-
+
private async Task GetWorkflowExecutionContextAsync(string workflowInstanceId, CancellationToken cancellationToken)
{
var workflowInstance = await workflowInstanceManager.FindByIdAsync(workflowInstanceId, cancellationToken);
if (workflowInstance == null)
return null;
-
+
var workflowState = workflowInstance.WorkflowState;
+
+ return await GetWorkflowExecutionContextAsync(workflowState, cancellationToken);
+ }
+
+ private async Task GetWorkflowExecutionContextAsync(WorkflowState workflowState, CancellationToken cancellationToken)
+ {
var workflowGraph = await workflowDefinitionService.FindWorkflowGraphAsync(workflowState.DefinitionVersionId, cancellationToken);
-
+
if (workflowGraph == null)
return null;
-
+
return await WorkflowExecutionContext.CreateAsync(
serviceProvider,
workflowGraph,
diff --git a/src/modules/Elsa.Workflows.Runtime/Providers/ClrWorkflowsProvider.cs b/src/modules/Elsa.Workflows.Runtime/Providers/ClrWorkflowsProvider.cs
index e76ffb413..1f5eda689 100644
--- a/src/modules/Elsa.Workflows.Runtime/Providers/ClrWorkflowsProvider.cs
+++ b/src/modules/Elsa.Workflows.Runtime/Providers/ClrWorkflowsProvider.cs
@@ -51,6 +51,6 @@ public class ClrWorkflowsProvider(
};
var materializerContext = new ClrWorkflowMaterializerContext(workflowBuilder.GetType());
- return new MaterializedWorkflow(workflow, Name, ClrWorkflowMaterializer.MaterializerName, materializerContext);
+ return new(workflow, Name, ClrWorkflowMaterializer.MaterializerName, materializerContext);
}
}
\ No newline at end of file
diff --git a/test/component/Elsa.Workflows.ComponentTests/Helpers/Fixtures/WorkflowServer.cs b/test/component/Elsa.Workflows.ComponentTests/Helpers/Fixtures/WorkflowServer.cs
index 44b321da3..aeae8967e 100644
--- a/test/component/Elsa.Workflows.ComponentTests/Helpers/Fixtures/WorkflowServer.cs
+++ b/test/component/Elsa.Workflows.ComponentTests/Helpers/Fixtures/WorkflowServer.cs
@@ -12,7 +12,6 @@ using Elsa.Testing.Shared.Handlers;
using Elsa.Testing.Shared.Services;
using Elsa.Workflows.ComponentTests.Decorators;
using Elsa.Workflows.ComponentTests.Materializers;
-using Elsa.Workflows.ComponentTests.Services;
using Elsa.Workflows.ComponentTests.WorkflowProviders;
using Elsa.Workflows.Management;
using Elsa.Workflows.Runtime.Distributed.Extensions;
diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/BulkDispatchWorkflows/BulkDispatchWorkflowsTests.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/BulkDispatchWorkflows/BulkDispatchWorkflowsTests.cs
new file mode 100644
index 000000000..de37ed7c7
--- /dev/null
+++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/BulkDispatchWorkflows/BulkDispatchWorkflowsTests.cs
@@ -0,0 +1,177 @@
+using Elsa.Common.Models;
+using Elsa.Testing.Shared;
+using Elsa.Testing.Shared.Models;
+using Elsa.Testing.Shared.Services;
+using Elsa.Workflows.Activities;
+using Elsa.Workflows.ComponentTests.Abstractions;
+using Elsa.Workflows.ComponentTests.Fixtures;
+using Elsa.Workflows.ComponentTests.Scenarios.Activities.BulkDispatchWorkflows.Workflows;
+using Elsa.Workflows.Management;
+using Elsa.Workflows.Models;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Elsa.Workflows.ComponentTests.Scenarios.Activities.BulkDispatchWorkflows;
+
+public class BulkDispatchWorkflowsTests : AppComponentTest
+{
+ private readonly AsyncWorkflowRunner _workflowRunner;
+
+ public BulkDispatchWorkflowsTests(App app) : base(app)
+ {
+ _workflowRunner = Scope.ServiceProvider.GetRequiredService();
+ }
+
+ [Fact(DisplayName = "BulkDispatchWorkflows should wait for all child workflows to complete")]
+ public async Task BulkDispatchAndWait_ShouldWaitForAllChildWorkflowsToComplete()
+ {
+ var result = await RunWorkflowAsync(BulkDispatchAndWaitWorkflow.DefinitionId);
+
+ var writeLineExecutionRecords = result.ActivityExecutionRecords.Where(x => x.ActivityType == "Elsa.WriteLine").ToList();
+ Assert.Equal(4, writeLineExecutionRecords.Count);
+ }
+
+ [Fact(DisplayName = "BulkDispatchWorkflows should dispatch and not wait when WaitForCompletion is false")]
+ public async Task BulkDispatchFireAndForget_ShouldNotWaitForChildWorkflows()
+ {
+ var expectedChildCount = 3;
+
+ // Run the main workflow and wait for child workflows to complete
+ var (result, completedChildWorkflows) = await RunWorkflowAndWaitForChildWorkflowsAsync(
+ BulkDispatchFireAndForgetWorkflow.DefinitionId,
+ SlowBulkChildWorkflow.DefinitionId,
+ expectedChildCount);
+
+ AssertWorkflowFinished(result);
+ var mainWorkflowCompletedAt = result.WorkflowExecutionContext.UpdatedAt;
+
+ // Assert that all child workflows completed after the main workflow
+ Assert.Equal(expectedChildCount, completedChildWorkflows.Count);
+ foreach (var childContext in completedChildWorkflows)
+ {
+ Assert.True(childContext.UpdatedAt > mainWorkflowCompletedAt,
+ $"Child workflow should complete after main workflow. Main: {mainWorkflowCompletedAt}, Child: {childContext.UpdatedAt}");
+ }
+ }
+
+ [Fact(DisplayName = "BulkDispatchWorkflows should use CorrelationIdFunction")]
+ public async Task BulkDispatchWithCorrelationId_ShouldUseCorrelationIdFunction()
+ {
+ var expectedChildCount = 3;
+
+ // Run the main workflow and wait for child workflows to complete
+ var (result, completedChildWorkflows) = await RunWorkflowAndWaitForChildWorkflowsAsync(
+ BulkDispatchWithCorrelationIdWorkflow.DefinitionId,
+ BulkChildWorkflow.DefinitionId,
+ expectedChildCount);
+
+ AssertWorkflowFinished(result);
+
+ // Assert that all child workflows have the expected correlation IDs based on the CorrelationIdFunction
+ Assert.Equal(expectedChildCount, completedChildWorkflows.Count);
+
+ var expectedCorrelationIds = new[] { "correlation-1", "correlation-2", "correlation-3" };
+ var actualCorrelationIds = completedChildWorkflows.Select(c => c.CorrelationId).OrderBy(c => c).ToList();
+
+ Assert.Equal(expectedCorrelationIds, actualCorrelationIds);
+ }
+
+ [Fact(DisplayName = "BulkDispatchWorkflows should execute ChildFaulted ports")]
+ public async Task BulkDispatchWithChildPorts_ShouldExecuteChildFaultedPortForFaultedWorkflows()
+ {
+ var result = await RunWorkflowAsync(BulkDispatchWithChildPortsWorkflow.DefinitionId);
+ AssertWorkflowFinished(result);
+
+ var faultedCount = await GetWorkflowVariableAsync(result, "FaultedCount");
+ Assert.Equal(3, faultedCount);
+ }
+
+ [Fact(DisplayName = "BulkDispatchWorkflows should complete immediately when Items is empty")]
+ public async Task BulkDispatchWithEmptyItems_ShouldCompleteImmediately()
+ {
+ var result = await RunWorkflowAsync(BulkDispatchEmptyItemsWorkflow.DefinitionId);
+ AssertWorkflowFinished(result);
+ }
+
+ [Fact(DisplayName = "BulkDispatchWorkflows should throw when workflow definition not found")]
+ public async Task BulkDispatchWithInvalidWorkflowDefinitionId_ShouldThrow()
+ {
+ var result = await RunWorkflowAsync(BulkDispatchInvalidDefinitionWorkflow.DefinitionId);
+ Assert.Equal(WorkflowSubStatus.Faulted, result.WorkflowExecutionContext.SubStatus);
+ }
+
+ [Fact(DisplayName = "BulkDispatchWorkflows child workflows should receive current item")]
+ public async Task BulkDispatchWorkflows_ChildWorkflowsShouldReceiveCurrentItem()
+ {
+ var result = await RunWorkflowAsync(MixFruitsWorkflow.DefinitionId);
+ AssertWorkflowFinished(result);
+
+ var writeLineExecutionRecords = result.ActivityExecutionRecords.Where(x => x.ActivityType == "Elsa.WriteLine").ToList();
+ Assert.Equal(3, writeLineExecutionRecords.Count);
+
+ var writtenTexts = writeLineExecutionRecords
+ .Select(x => x.ActivityState?[nameof(WriteLine.Text)] as string)
+ .ToList();
+
+ Assert.Contains("Mixing Apple", writtenTexts);
+ Assert.Contains("Mixing Banana", writtenTexts);
+ Assert.Contains("Mixing Cherry", writtenTexts);
+ }
+
+ private Task RunWorkflowAsync(string workflowDefinitionId)
+ {
+ return _workflowRunner.RunAndAwaitWorkflowCompletionAsync(WorkflowDefinitionHandle.ByDefinitionId(workflowDefinitionId, VersionOptions.Published));
+ }
+
+ private static void AssertWorkflowFinished(TestWorkflowExecutionResult result)
+ {
+ Assert.Equal(WorkflowSubStatus.Finished, result.WorkflowExecutionContext.SubStatus);
+ }
+
+ private async Task GetWorkflowVariableAsync(TestWorkflowExecutionResult result, string variableName)
+ {
+ var variableManager = Scope.ServiceProvider.GetRequiredService();
+ var variables = await variableManager.GetVariablesAsync(result.WorkflowExecutionContext);
+ return (T?)variables.FirstOrDefault(v => v.Variable.Name == variableName)?.Value;
+ }
+
+ private async Task<(TestWorkflowExecutionResult Result, List CompletedChildWorkflows)> RunWorkflowAndWaitForChildWorkflowsAsync(
+ string parentWorkflowDefinitionId,
+ string childWorkflowDefinitionId,
+ int expectedChildCount)
+ {
+ var workflowEvents = Scope.ServiceProvider.GetRequiredService();
+ var completedChildWorkflows = new List();
+ var childWorkflowCompletionTcs = new TaskCompletionSource();
+
+ // Subscribe to child workflow completion events
+ void OnWorkflowStateCommitted(object? sender, WorkflowStateCommittedEventArgs e)
+ {
+ if (e.WorkflowExecutionContext.Workflow.Identity.DefinitionId != childWorkflowDefinitionId ||
+ e.WorkflowExecutionContext.Status != WorkflowStatus.Finished)
+ {
+ return;
+ }
+
+ completedChildWorkflows.Add(e.WorkflowExecutionContext);
+ if (completedChildWorkflows.Count == expectedChildCount)
+ childWorkflowCompletionTcs.TrySetResult();
+ }
+
+ workflowEvents.WorkflowStateCommitted += OnWorkflowStateCommitted;
+
+ try
+ {
+ // Run the main workflow
+ var result = await RunWorkflowAsync(parentWorkflowDefinitionId);
+
+ // Wait for all child workflows to complete
+ await childWorkflowCompletionTcs.Task;
+
+ return (result, completedChildWorkflows);
+ }
+ finally
+ {
+ workflowEvents.WorkflowStateCommitted -= OnWorkflowStateCommitted;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/BulkDispatchWorkflows/Workflows/FruitWorkflow.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/BulkDispatchWorkflows/Workflows/BulkChildWorkflow.cs
similarity index 60%
rename from test/component/Elsa.Workflows.ComponentTests/Scenarios/BulkDispatchWorkflows/Workflows/FruitWorkflow.cs
rename to test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/BulkDispatchWorkflows/Workflows/BulkChildWorkflow.cs
index 42d91876d..6734738f3 100644
--- a/test/component/Elsa.Workflows.ComponentTests/Scenarios/BulkDispatchWorkflows/Workflows/FruitWorkflow.cs
+++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/BulkDispatchWorkflows/Workflows/BulkChildWorkflow.cs
@@ -1,12 +1,11 @@
using Elsa.Extensions;
using Elsa.Workflows.Activities;
-using Elsa.Workflows.ComponentTests.Activities;
using JetBrains.Annotations;
-namespace Elsa.Workflows.ComponentTests.Scenarios.BulkDispatchWorkflows.Workflows;
+namespace Elsa.Workflows.ComponentTests.Scenarios.Activities.BulkDispatchWorkflows.Workflows;
[UsedImplicitly]
-public class FruitWorkflow : WorkflowBase
+public class BulkChildWorkflow : WorkflowBase
{
public static readonly string DefinitionId = Guid.NewGuid().ToString();
@@ -14,13 +13,13 @@ public class FruitWorkflow : WorkflowBase
{
builder.WithDefinitionId(DefinitionId);
var item = builder.WithInput("Item");
+
builder.Root = new Sequence
{
Activities =
{
- new WriteLine(x => $"Mixing {x.GetInput(item)}"),
- new TriggerSignal(x => x.GetInput(item))
+ new WriteLine(context => $"Processing item: {context.GetInput(item)}")
}
};
}
-}
\ No newline at end of file
+}
diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/BulkDispatchWorkflows/Workflows/BulkDispatchAndWaitWorkflow.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/BulkDispatchWorkflows/Workflows/BulkDispatchAndWaitWorkflow.cs
new file mode 100644
index 000000000..07dc906bd
--- /dev/null
+++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/BulkDispatchWorkflows/Workflows/BulkDispatchAndWaitWorkflow.cs
@@ -0,0 +1,26 @@
+using Elsa.Workflows.Activities;
+
+namespace Elsa.Workflows.ComponentTests.Scenarios.Activities.BulkDispatchWorkflows.Workflows;
+
+public class BulkDispatchAndWaitWorkflow : WorkflowBase
+{
+ public static readonly string DefinitionId = Guid.NewGuid().ToString();
+
+ protected override void Build(IWorkflowBuilder builder)
+ {
+ builder.WithDefinitionId(DefinitionId);
+ builder.Root = new Sequence
+ {
+ Activities =
+ {
+ new Runtime.Activities.BulkDispatchWorkflows
+ {
+ WorkflowDefinitionId = new(BulkChildWorkflow.DefinitionId),
+ Items = new(new object[] { 1, 2, 3 }),
+ WaitForCompletion = new(true)
+ },
+ new WriteLine("Done")
+ }
+ };
+ }
+}
diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/BulkDispatchWorkflows/Workflows/BulkDispatchEmptyItemsWorkflow.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/BulkDispatchWorkflows/Workflows/BulkDispatchEmptyItemsWorkflow.cs
new file mode 100644
index 000000000..21ce9b79d
--- /dev/null
+++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/BulkDispatchWorkflows/Workflows/BulkDispatchEmptyItemsWorkflow.cs
@@ -0,0 +1,21 @@
+using JetBrains.Annotations;
+
+namespace Elsa.Workflows.ComponentTests.Scenarios.Activities.BulkDispatchWorkflows.Workflows;
+
+[UsedImplicitly]
+public class BulkDispatchEmptyItemsWorkflow : WorkflowBase
+{
+ public static readonly string DefinitionId = nameof(BulkDispatchEmptyItemsWorkflow);
+
+ protected override void Build(IWorkflowBuilder builder)
+ {
+ builder.WithDefinitionId(DefinitionId);
+
+ builder.Root = new Runtime.Activities.BulkDispatchWorkflows
+ {
+ WorkflowDefinitionId = new(BulkChildWorkflow.DefinitionId),
+ Items = new(Array.Empty