Add WorkflowStateCommitted notification support and update state handling logic

- Introduced `WorkflowStateCommitted` notification to encapsulate workflow execution context, state, and instance details.
- Updated `DefaultCommitStateHandler` to publish `WorkflowStateCommitted` via `IMediator`.
- Adjusted `DispatchWorkflowExtensions` to use `WorkflowStateCommitted` for workflow completion.
This commit is contained in:
Sipke Schoorstra 2025-09-17 21:25:55 +02:00
parent 6dfce283b2
commit 18fe3e827a
No known key found for this signature in database
GPG key ID: 5C10502B28A4268F
3 changed files with 21 additions and 6 deletions

View file

@ -5,6 +5,7 @@ using Elsa.Workflows;
using Elsa.Workflows.Notifications;
using Elsa.Workflows.Runtime;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Notifications;
using Elsa.Workflows.Runtime.Requests;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@ -13,7 +14,7 @@ namespace Elsa.Testing.Shared;
public static class DispatchWorkflowExtensions
{
public static async Task<WorkflowFinished?> DispatchWorkflowAndRunToCompletion(
public static async Task<WorkflowStateCommitted?> DispatchWorkflowAndRunToCompletion(
this IWorkflow workflowDefinition,
Action<IServiceCollection>? configureServices = null,
Action<IModule>? configureElsa = null,
@ -21,7 +22,7 @@ public static class DispatchWorkflowExtensions
TimeSpan? timeout = null)
{
var semaphore = new SemaphoreSlim(0, 1);
WorkflowFinished? workflowFinishedRecord = null;
WorkflowStateCommitted? workflowFinishedRecord = null;
var host = Host.CreateDefaultBuilder()
.ConfigureServices(services =>
@ -29,8 +30,11 @@ public static class DispatchWorkflowExtensions
configureServices?.Invoke(services);
// This notification handler will capture the WorkflowFinished record (to be returned) and release the semaphore.
services.AddNotificationHandler<WorkflowFinishedAction, WorkflowFinished>(sp => new(notification =>
services.AddNotificationHandler<WorkflowFinishedAction, WorkflowStateCommitted>(sp => new(notification =>
{
if (notification.WorkflowExecutionContext.Status != WorkflowStatus.Finished)
return;
workflowFinishedRecord = notification;
semaphore.Release();
}));
@ -75,9 +79,9 @@ public static class DispatchWorkflowExtensions
}
}
class WorkflowFinishedAction(Action<WorkflowFinished> action) : INotificationHandler<WorkflowFinished>
class WorkflowFinishedAction(Action<WorkflowStateCommitted> action) : INotificationHandler<WorkflowStateCommitted>
{
public Task HandleAsync(WorkflowFinished notification, CancellationToken cancellationToken)
public Task HandleAsync(WorkflowStateCommitted notification, CancellationToken cancellationToken)
{
action(notification);
return Task.CompletedTask;

View file

@ -0,0 +1,7 @@
using Elsa.Mediator.Contracts;
using Elsa.Workflows.Management.Entities;
using Elsa.Workflows.State;
namespace Elsa.Workflows.Runtime.Notifications;
public record WorkflowStateCommitted(WorkflowExecutionContext WorkflowExecutionContext, WorkflowState WorkflowState, WorkflowInstance WorkflowInstance) : INotification;

View file

@ -1,6 +1,8 @@
using Elsa.Mediator.Contracts;
using Elsa.Workflows.CommitStates;
using Elsa.Workflows.Management;
using Elsa.Workflows.Runtime.Entities;
using Elsa.Workflows.Runtime.Notifications;
using Elsa.Workflows.Runtime.Requests;
using Elsa.Workflows.State;
@ -10,6 +12,7 @@ public class DefaultCommitStateHandler(
IWorkflowInstanceManager workflowInstanceManager,
IBookmarksPersister bookmarkPersister,
IVariablePersistenceManager variablePersistenceManager,
IMediator mediator,
ILogRecordSink<ActivityExecutionRecord> activityExecutionLogRecordSink,
ILogRecordSink<WorkflowExecutionLogRecord> workflowExecutionLogRecordSink) : ICommitStateHandler
{
@ -26,9 +29,10 @@ public class DefaultCommitStateHandler(
await activityExecutionLogRecordSink.PersistExecutionLogsAsync(workflowExecutionContext, cancellationToken);
await workflowExecutionLogRecordSink.PersistExecutionLogsAsync(workflowExecutionContext, cancellationToken);
await variablePersistenceManager.SaveVariablesAsync(workflowExecutionContext);
await workflowInstanceManager.SaveAsync(workflowState, cancellationToken);
var workflowInstance = await workflowInstanceManager.SaveAsync(workflowState, cancellationToken);
workflowExecutionContext.ExecutionLog.Clear();
workflowExecutionContext.ClearCompletedActivityExecutionContexts();
await workflowExecutionContext.ExecuteDeferredTasksAsync();
await mediator.SendAsync(new WorkflowStateCommitted(workflowExecutionContext, workflowState, workflowInstance), cancellationToken);
}
}