* Isolate background workflow dispatches from caller's cancellation token When dispatching multiple child workflows, early child completions cancel the parent activity's token while dispatches are still in progress. This creates a race condition where remaining dispatches fail with OperationCanceledException. * Make BackgroundWorkflowDispatcher & BackgroundStimulusDispatcher caller Cts-independent
31 lines
1.1 KiB
C#
31 lines
1.1 KiB
C#
using Elsa.Common.Multitenancy;
|
|
using Elsa.Mediator;
|
|
using Elsa.Mediator.Contracts;
|
|
using Elsa.Tenants.Mediator;
|
|
using Elsa.Workflows.Runtime.Commands;
|
|
using Elsa.Workflows.Runtime.Requests;
|
|
using Elsa.Workflows.Runtime.Responses;
|
|
|
|
namespace Elsa.Workflows.Runtime;
|
|
|
|
/// <summary>
|
|
/// A simple implementation that queues the specified request for delivering stimuli on a non-durable background worker.
|
|
/// </summary>
|
|
public class BackgroundStimulusDispatcher(ICommandSender commandSender, ITenantAccessor tenantAccessor) : IStimulusDispatcher
|
|
{
|
|
/// <inheritdoc />
|
|
public async Task<DispatchStimulusResponse> SendAsync(DispatchStimulusRequest request, CancellationToken cancellationToken = default)
|
|
{
|
|
var command = new DispatchStimulusCommand(request);
|
|
|
|
// Background commands run independently of caller's lifecycle.
|
|
await commandSender.SendAsync(command, CommandStrategy.Background, CreateHeaders(), CancellationToken.None);
|
|
return DispatchStimulusResponse.Empty;
|
|
}
|
|
|
|
private IDictionary<object, object> CreateHeaders()
|
|
{
|
|
return TenantHeaders.CreateHeaders(tenantAccessor.Tenant?.Id);
|
|
}
|
|
}
|