diff --git a/src/clients/Elsa.Api.Client/Extensions/ActivityExtensions.cs b/src/clients/Elsa.Api.Client/Extensions/ActivityExtensions.cs
index 6ae48eab8..f39fc90bc 100644
--- a/src/clients/Elsa.Api.Client/Extensions/ActivityExtensions.cs
+++ b/src/clients/Elsa.Api.Client/Extensions/ActivityExtensions.cs
@@ -1,4 +1,5 @@
using System.Text.Json.Nodes;
+using Elsa.Api.Client.Resources.WorkflowDefinitions.Models;
using Elsa.Api.Client.Shared.Models;
namespace Elsa.Api.Client.Extensions;
@@ -182,4 +183,14 @@ public static class ActivityExtensions
/// Sets a value indicating whether the specified activity can trigger the workflow.
///
public static void SetRunAsynchronously(this JsonObject activity, bool value) => activity.SetProperty(JsonValue.Create(value), "customProperties", "runAsynchronously");
+
+ ///
+ /// Gets the commit state behavior for the specified activity.
+ ///
+ public static ActivityCommitStateBehavior GetCommitStateBehavior(this JsonObject activity) => activity.TryGetProperty("customProperties", "commitStateBehavior") ?? ActivityCommitStateBehavior.Default;
+
+ ///
+ /// Sets the commit state behavior for the specified activity.
+ ///
+ public static void SetCommitStateBehavior(this JsonObject activity, ActivityCommitStateBehavior value) => activity.SetProperty(JsonValue.Create(value.ToString()), "customProperties", "commitStateBehavior");
}
\ No newline at end of file
diff --git a/src/clients/Elsa.Api.Client/Extensions/JsonObjectExtensions.cs b/src/clients/Elsa.Api.Client/Extensions/JsonObjectExtensions.cs
index a1612f9c2..b65fcf394 100644
--- a/src/clients/Elsa.Api.Client/Extensions/JsonObjectExtensions.cs
+++ b/src/clients/Elsa.Api.Client/Extensions/JsonObjectExtensions.cs
@@ -15,52 +15,43 @@ public static class JsonObjectExtensions
{
return obj.ContainsKey("type") && obj.ContainsKey("id") && obj.ContainsKey("version");
}
-
+
///
/// Serializes the specified value to a .
///
/// The value to serialize.
/// The to use.
/// A representing the specified value.
- public static JsonNode SerializeToNode(this object value, JsonSerializerOptions? options = default)
+ public static JsonNode SerializeToNode(this object value, JsonSerializerOptions? options = null)
{
- options ??= new JsonSerializerOptions
- {
- PropertyNamingPolicy = JsonNamingPolicy.CamelCase
- };
-
+ options ??= new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
+
return JsonSerializer.SerializeToNode(value, options)!;
}
-
+
///
/// Serializes the specified value to a .
///
/// The value to serialize.
/// The to use.
/// A representing the specified value.
- public static JsonArray SerializeToArray(this object value, JsonSerializerOptions? options = default)
+ public static JsonArray SerializeToArray(this object value, JsonSerializerOptions? options = null)
{
- options ??= new JsonSerializerOptions
- {
- PropertyNamingPolicy = JsonNamingPolicy.CamelCase
- };
-
+ options ??= new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
+
return JsonSerializer.SerializeToNode(value, options)!.AsArray();
}
-
+
///
/// Serializes the specified value to a .
///
/// The value to serialize.
/// The to use.
/// A representing the specified value.
- public static JsonArray SerializeToArray(this IEnumerable value, JsonSerializerOptions? options = default)
+ public static JsonArray SerializeToArray(this IEnumerable value, JsonSerializerOptions? options = null)
{
- options ??= new JsonSerializerOptions
- {
- PropertyNamingPolicy = JsonNamingPolicy.CamelCase
- };
-
+ options ??= new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
+
return JsonSerializer.SerializeToNode(value, options)!.AsArray();
}
@@ -71,19 +62,23 @@ public static class JsonObjectExtensions
/// The to use.
/// The type to deserialize to.
/// The deserialized value.
- public static T Deserialize(this JsonNode value, JsonSerializerOptions? options = default)
+ public static T Deserialize(this JsonNode value, JsonSerializerOptions? options = null)
{
- options ??= new JsonSerializerOptions
- {
- PropertyNamingPolicy = JsonNamingPolicy.CamelCase
- };
-
+ options ??= new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
+
if (value is JsonObject jsonObject)
return JsonSerializer.Deserialize(jsonObject, options)!;
if (value is JsonArray jsonArray)
return JsonSerializer.Deserialize(jsonArray, options)!;
+ if (typeof(T).IsEnum || (Nullable.GetUnderlyingType(typeof(T))?.IsEnum ?? false))
+ {
+ if (value.GetValueKind() == JsonValueKind.Null)
+ return default!;
+ return (T)Enum.Parse(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T), value.ToString());
+ }
+
if (value is JsonValue jsonValue)
return jsonValue.GetValue();
@@ -101,7 +96,7 @@ public static class JsonObjectExtensions
model = GetPropertyContainer(model, path);
model[path.Last()] = value?.SerializeToNode();
}
-
+
///
/// Sets the property value of the specified model.
///
@@ -113,7 +108,7 @@ public static class JsonObjectExtensions
model = GetPropertyContainer(model, path);
model[path.Last()] = value?.SerializeToNode();
}
-
+
///
/// Sets the property value of the specified model.
///
@@ -125,7 +120,7 @@ public static class JsonObjectExtensions
model = GetPropertyContainer(model, path);
model[path.Last()] = new JsonArray(value.Select(x => x.SerializeToNode()).ToArray());
}
-
+
///
/// Gets the property value of the specified model.
///
@@ -139,7 +134,7 @@ public static class JsonObjectExtensions
foreach (var prop in path.SkipLast(1))
{
if (currentModel[prop] is not JsonObject value)
- return default;
+ return null;
currentModel = value;
}
@@ -147,6 +142,25 @@ public static class JsonObjectExtensions
return currentModel[path.Last()];
}
+ ///
+ /// Gets the property value of the specified model.
+ ///
+ /// The model to get the property value from.
+ /// The path to the property.
+ /// The type to deserialize to.
+ /// The property value.
+ public static T? TryGetProperty(this JsonObject model, params string[] path)
+ {
+ try
+ {
+ return model.GetProperty(path);
+ }
+ catch (Exception e)
+ {
+ return default;
+ }
+ }
+
///
/// Gets the property value of the specified model.
///
@@ -173,7 +187,7 @@ public static class JsonObjectExtensions
var property = GetProperty(model, path);
return property != null ? property.Deserialize(options) : default;
}
-
+
///
/// Returns the property container of the specified model.
///
@@ -190,5 +204,4 @@ public static class JsonObjectExtensions
return model;
}
-
}
\ No newline at end of file
diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/ActivityCommitStateBehavior.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/ActivityCommitStateBehavior.cs
new file mode 100644
index 000000000..66d6dbdf6
--- /dev/null
+++ b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/ActivityCommitStateBehavior.cs
@@ -0,0 +1,29 @@
+namespace Elsa.Api.Client.Resources.WorkflowDefinitions.Models;
+
+public enum ActivityCommitStateBehavior
+{
+ ///
+ /// Never commit state, regardless of the workflow commit state options.
+ ///
+ Never,
+
+ ///
+ /// Look at the workflow commit state options to determine if state should be committed.
+ ///
+ Default,
+
+ ///
+ /// Commit state before the activity starts.
+ ///
+ Executing,
+
+ ///
+ /// Commit state after the activity executes.
+ ///
+ Executed,
+
+ ///
+ /// Commit state before the activity starts and after the activity executes.
+ ///
+ BeforeAndAfterExecution
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowCommitStateOptions.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowCommitStateOptions.cs
new file mode 100644
index 000000000..8e14345c6
--- /dev/null
+++ b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowCommitStateOptions.cs
@@ -0,0 +1,19 @@
+namespace Elsa.Api.Client.Resources.WorkflowDefinitions.Models;
+
+public class WorkflowCommitStateOptions
+{
+ ///
+ /// Commit workflow state before the workflow starts.
+ ///
+ public bool Starting { get; set; }
+
+ ///
+ /// Commit workflow state before an activity executes, unless the activity is configured to not commit state.
+ ///
+ public bool ActivityExecuting { get; set; }
+
+ ///
+ /// Commit workflow state after an activity executes, unless the activity is configured to not commit state.
+ ///
+ public bool ActivityExecuted { get; set; }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowOptions.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowOptions.cs
index ec28ac197..c3f38f381 100644
--- a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowOptions.cs
+++ b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowOptions.cs
@@ -29,4 +29,9 @@ public class WorkflowOptions
/// The type of IIncidentStrategy to use when a fault occurs in the workflow.
///
public string? IncidentStrategyType { get; set; }
+
+ ///
+ /// The options for committing workflow state.
+ ///
+ public WorkflowCommitStateOptions CommitStateOptions { get; set; } = new();
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Contexts/WorkflowExecutionContext.cs b/src/modules/Elsa.Workflows.Core/Contexts/WorkflowExecutionContext.cs
index 56788e661..df38d706d 100644
--- a/src/modules/Elsa.Workflows.Core/Contexts/WorkflowExecutionContext.cs
+++ b/src/modules/Elsa.Workflows.Core/Contexts/WorkflowExecutionContext.cs
@@ -37,6 +37,7 @@ public partial class WorkflowExecutionContext : IExecutionContext
private readonly IList _completionCallbackEntries = new List();
private IList _activityExecutionContexts;
private readonly IHasher _hasher;
+ private readonly ICommitStateHandler _commitStateHandler;
///
/// Initializes a new instance of .
@@ -61,6 +62,7 @@ public partial class WorkflowExecutionContext : IExecutionContext
ActivityRegistry = serviceProvider.GetRequiredService();
ActivityRegistryLookup = serviceProvider.GetRequiredService();
_hasher = serviceProvider.GetRequiredService();
+ _commitStateHandler = serviceProvider.GetRequiredService();
SubStatus = WorkflowSubStatus.Pending;
Id = id;
CorrelationId = correlationId;
@@ -238,6 +240,11 @@ public partial class WorkflowExecutionContext : IExecutionContext
/// The current sub status of the workflow.
public WorkflowSubStatus SubStatus { get; internal set; }
+ ///
+ /// The previous sub status of the workflow.
+ ///
+ public WorkflowSubStatus PreviousSubStatus { get; internal set; }
+
/// The root associated with the execution context.
public MemoryRegister MemoryRegister { get; private set; } = null!;
@@ -510,8 +517,9 @@ public partial class WorkflowExecutionContext : IExecutionContext
internal void TransitionTo(WorkflowSubStatus subStatus)
{
if (!ValidateStatusTransition())
- throw new Exception($"Cannot transition from {SubStatus} to {subStatus}");
+ throw new($"Cannot transition from {SubStatus} to {subStatus}");
+ PreviousSubStatus = SubStatus;
SubStatus = subStatus;
UpdatedAt = SystemClock.UtcNow;
@@ -614,4 +622,9 @@ public partial class WorkflowExecutionContext : IExecutionContext
var currentMainStatus = GetMainStatus(SubStatus);
return currentMainStatus != WorkflowStatus.Finished;
}
+
+ public Task CommitAsync()
+ {
+ return _commitStateHandler.CommitAsync(this, CancellationToken);
+ }
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Contracts/ICommitStateHandler.cs b/src/modules/Elsa.Workflows.Core/Contracts/ICommitStateHandler.cs
index 3d24ee6fd..a73659ea5 100644
--- a/src/modules/Elsa.Workflows.Core/Contracts/ICommitStateHandler.cs
+++ b/src/modules/Elsa.Workflows.Core/Contracts/ICommitStateHandler.cs
@@ -4,5 +4,6 @@ namespace Elsa.Workflows;
public interface ICommitStateHandler
{
+ Task CommitAsync(WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken = default);
Task CommitAsync(WorkflowExecutionContext workflowExecutionContext, WorkflowState workflowState, CancellationToken cancellationToken = default);
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Elsa.Workflows.Core.csproj.DotSettings b/src/modules/Elsa.Workflows.Core/Elsa.Workflows.Core.csproj.DotSettings
index f05e636df..300c67063 100644
--- a/src/modules/Elsa.Workflows.Core/Elsa.Workflows.Core.csproj.DotSettings
+++ b/src/modules/Elsa.Workflows.Core/Elsa.Workflows.Core.csproj.DotSettings
@@ -7,6 +7,8 @@
True
True
True
+ True
+ True
True
True
True
diff --git a/src/modules/Elsa.Workflows.Core/Enums/ActivityCommitStateBehavior.cs b/src/modules/Elsa.Workflows.Core/Enums/ActivityCommitStateBehavior.cs
new file mode 100644
index 000000000..3ae3e3062
--- /dev/null
+++ b/src/modules/Elsa.Workflows.Core/Enums/ActivityCommitStateBehavior.cs
@@ -0,0 +1,29 @@
+namespace Elsa.Workflows;
+
+public enum ActivityCommitStateBehavior
+{
+ ///
+ /// Never commit state, regardless of the workflow commit state options.
+ ///
+ Never,
+
+ ///
+ /// Look at the workflow commit state options to determine if state should be committed.
+ ///
+ Default,
+
+ ///
+ /// Commit state before the activity starts.
+ ///
+ Executing,
+
+ ///
+ /// Commit state after the activity executes.
+ ///
+ Executed,
+
+ ///
+ /// Commit state before the activity starts and after the activity executes.
+ ///
+ BeforeAndAfterExecution
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Extensions/ActivityPropertyExtensions.cs b/src/modules/Elsa.Workflows.Core/Extensions/ActivityPropertyExtensions.cs
index 4d657080a..b4c240157 100644
--- a/src/modules/Elsa.Workflows.Core/Extensions/ActivityPropertyExtensions.cs
+++ b/src/modules/Elsa.Workflows.Core/Extensions/ActivityPropertyExtensions.cs
@@ -11,6 +11,7 @@ public static class ActivityPropertyExtensions
private static readonly string[] CanStartWorkflowPropertyName = ["canStartWorkflow", "CanStartWorkflow"];
private static readonly string[] RunAsynchronouslyPropertyName = ["runAsynchronously", "RunAsynchronously"];
private static readonly string[] SourcePropertyName = ["source", "Source"];
+ private static readonly string[] CommitStateBehaviorName = ["commitStateBehavior", "CommitStateBehavior"];
///
/// Gets a flag indicating whether this activity can be used for starting a workflow.
@@ -46,6 +47,16 @@ public static class ActivityPropertyExtensions
/// Sets the source file and line number where this activity was instantiated, if any.
///
public static void SetSource(this IActivity activity, string value) => activity.CustomProperties[SourcePropertyName[0]] = value;
+
+ ///
+ /// Gets the commit state behavior for the specified activity.
+ ///
+ public static ActivityCommitStateBehavior GetCommitStateBehavior(this IActivity activity) => activity.CustomProperties.GetValueOrDefault(CommitStateBehaviorName, () => ActivityCommitStateBehavior.Default);
+
+ ///
+ /// Sets the commit state behavior for the specified activity.
+ ///
+ public static void SetCommitStateBehavior(this IActivity activity, ActivityCommitStateBehavior value) => activity.CustomProperties[CommitStateBehaviorName[0]] = value;
///
/// Sets the source file and line number where this activity was instantiated, if any.
@@ -62,7 +73,7 @@ public static class ActivityPropertyExtensions
///
/// Gets the display text for the specified activity.
///
- public static string? GetDisplayText(this IActivity activity) => activity.Metadata.TryGetValue("displayText", out var value) ? value.ToString() : default;
+ public static string? GetDisplayText(this IActivity activity) => activity.Metadata.TryGetValue("displayText", out var value) ? value.ToString() : null;
///
/// Sets the display text for the specified activity.
@@ -72,7 +83,7 @@ public static class ActivityPropertyExtensions
///
/// Gets the description for the specified activity.
///
- public static string? GetDescription(this IActivity activity) => activity.Metadata.TryGetValue("description", out var value) ? value.ToString() : default;
+ public static string? GetDescription(this IActivity activity) => activity.Metadata.TryGetValue("description", out var value) ? value.ToString() : null;
///
/// Sets the description for the specified activity.
diff --git a/src/modules/Elsa.Workflows.Core/Middleware/Activities/DefaultActivityInvokerMiddleware.cs b/src/modules/Elsa.Workflows.Core/Middleware/Activities/DefaultActivityInvokerMiddleware.cs
index 65652ea04..a7bd74c6b 100644
--- a/src/modules/Elsa.Workflows.Core/Middleware/Activities/DefaultActivityInvokerMiddleware.cs
+++ b/src/modules/Elsa.Workflows.Core/Middleware/Activities/DefaultActivityInvokerMiddleware.cs
@@ -47,6 +47,10 @@ public class DefaultActivityInvokerMiddleware(ActivityMiddlewareDelegate next, I
context.AddExecutionLogEntry("Precondition Failed", "Cannot execute at this time");
return;
}
+
+ // Conditionally commit the workflow state.
+ if(ShouldCommitWhenStarting(context))
+ await context.WorkflowExecutionContext.CommitAsync();
context.TransitionTo(ActivityStatus.Running);
@@ -78,6 +82,10 @@ public class DefaultActivityInvokerMiddleware(ActivityMiddlewareDelegate next, I
workflowExecutionContext.Bookmarks.AddRange(context.Bookmarks);
logger.LogDebug("Added {BookmarkCount} bookmarks to the workflow execution context", context.Bookmarks.Count);
}
+
+ // Conditionally commit the workflow state.
+ if(ShouldCommitWhenExecuted(context))
+ await context.WorkflowExecutionContext.CommitAsync();
}
///
@@ -111,4 +119,40 @@ public class DefaultActivityInvokerMiddleware(ActivityMiddlewareDelegate next, I
// Evaluate input properties.
await context.EvaluateInputPropertiesAsync();
}
+
+ private bool ShouldCommitWhenStarting(ActivityExecutionContext context)
+ {
+ var behavior = context.Activity.GetCommitStateBehavior();
+
+ if (behavior == ActivityCommitStateBehavior.Executing)
+ return true;
+
+ if (behavior == ActivityCommitStateBehavior.Default)
+ {
+ var workflowOptions = context.WorkflowExecutionContext.Workflow.Options.CommitStateOptions;
+
+ if(workflowOptions.ActivityExecuting)
+ return true;
+ }
+
+ return false;
+ }
+
+ private bool ShouldCommitWhenExecuted(ActivityExecutionContext context)
+ {
+ var behavior = context.Activity.GetCommitStateBehavior();
+
+ if (behavior == ActivityCommitStateBehavior.Executed)
+ return true;
+
+ if (behavior == ActivityCommitStateBehavior.Default)
+ {
+ var workflowOptions = context.WorkflowExecutionContext.Workflow.Options.CommitStateOptions;
+
+ if(workflowOptions.ActivityExecuted)
+ return true;
+ }
+
+ return false;
+ }
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Middleware/Workflows/DefaultActivitySchedulerMiddleware.cs b/src/modules/Elsa.Workflows.Core/Middleware/Workflows/DefaultActivitySchedulerMiddleware.cs
index f9d1645d9..078474b68 100644
--- a/src/modules/Elsa.Workflows.Core/Middleware/Workflows/DefaultActivitySchedulerMiddleware.cs
+++ b/src/modules/Elsa.Workflows.Core/Middleware/Workflows/DefaultActivitySchedulerMiddleware.cs
@@ -36,6 +36,8 @@ public class DefaultActivitySchedulerMiddleware : WorkflowExecutionMiddleware
context.TransitionTo(WorkflowSubStatus.Executing);
+ await ConditionallyCommitStateAsync(context);
+
while (scheduler.HasAny)
{
// Do not start a workflow if cancellation has been requested.
@@ -65,4 +67,12 @@ public class DefaultActivitySchedulerMiddleware : WorkflowExecutionMiddleware
await _activityInvoker.InvokeAsync(context, workItem.Activity, options);
}
+
+ private async Task ConditionallyCommitStateAsync(WorkflowExecutionContext context)
+ {
+ var shouldCommit = context.Workflow.Options.CommitStateOptions.Starting;
+
+ if (shouldCommit)
+ await context.CommitAsync();
+ }
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Models/WorkflowCommitStateOptions.cs b/src/modules/Elsa.Workflows.Core/Models/WorkflowCommitStateOptions.cs
new file mode 100644
index 000000000..514a255db
--- /dev/null
+++ b/src/modules/Elsa.Workflows.Core/Models/WorkflowCommitStateOptions.cs
@@ -0,0 +1,19 @@
+namespace Elsa.Workflows.Models;
+
+public class WorkflowCommitStateOptions
+{
+ ///
+ /// Commit workflow state before the workflow starts.
+ ///
+ public bool Starting { get; set; }
+
+ ///
+ /// Commit workflow state before an activity executes, unless the activity is configured to not commit state.
+ ///
+ public bool ActivityExecuting { get; set; }
+
+ ///
+ /// Commit workflow state after an activity executes, unless the activity is configured to not commit state.
+ ///
+ public bool ActivityExecuted { get; set; }
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Models/WorkflowOptions.cs b/src/modules/Elsa.Workflows.Core/Models/WorkflowOptions.cs
index e4b82b116..f2ac78484 100644
--- a/src/modules/Elsa.Workflows.Core/Models/WorkflowOptions.cs
+++ b/src/modules/Elsa.Workflows.Core/Models/WorkflowOptions.cs
@@ -29,4 +29,9 @@ public class WorkflowOptions
/// The type of to use when a fault occurs in the workflow.
///
public Type? IncidentStrategyType { get; set; }
+
+ ///
+ /// The options for committing workflow state.
+ ///
+ public WorkflowCommitStateOptions CommitStateOptions { get; set; } = new();
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Services/NoopCommitStateHandler.cs b/src/modules/Elsa.Workflows.Core/Services/NoopCommitStateHandler.cs
index 8503bddb7..e0a6b7f81 100644
--- a/src/modules/Elsa.Workflows.Core/Services/NoopCommitStateHandler.cs
+++ b/src/modules/Elsa.Workflows.Core/Services/NoopCommitStateHandler.cs
@@ -4,6 +4,11 @@ namespace Elsa.Workflows;
public class NoopCommitStateHandler : ICommitStateHandler
{
+ public Task CommitAsync(WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken = default)
+ {
+ return Task.CompletedTask;
+ }
+
public Task CommitAsync(WorkflowExecutionContext workflowExecutionContext, WorkflowState workflowState, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
diff --git a/src/modules/Elsa.Workflows.Runtime/Services/StoreCommitStateHandler.cs b/src/modules/Elsa.Workflows.Runtime/Services/StoreCommitStateHandler.cs
index 8f3d33466..5db9391ba 100644
--- a/src/modules/Elsa.Workflows.Runtime/Services/StoreCommitStateHandler.cs
+++ b/src/modules/Elsa.Workflows.Runtime/Services/StoreCommitStateHandler.cs
@@ -5,6 +5,12 @@ namespace Elsa.Workflows.Runtime;
public class StoreCommitStateHandler(IWorkflowInstanceManager workflowInstanceManager) : ICommitStateHandler
{
+ public async Task CommitAsync(WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken = default)
+ {
+ var workflowState = workflowInstanceManager.ExtractWorkflowState(workflowExecutionContext);
+ await CommitAsync(workflowExecutionContext, workflowState, cancellationToken);
+ }
+
public async Task CommitAsync(WorkflowExecutionContext workflowExecutionContext, WorkflowState workflowState, CancellationToken cancellationToken = default)
{
await workflowInstanceManager.SaveAsync(workflowState, cancellationToken);