Implement distributed lock for registry population (#4983)

* Implement distributed lock for registry population

Added distributed lock in 'PopulateRegistriesHostedService' to prevent concurrent registry updates. Also implemented a semaphore in 'DefaultWorkflowDefinitionStorePopulator' to control access to shared resources during add or update operations. This change helps to ensure the integrity and consistency of the workflow registries.

* Refactor dependency injection for IDistributedLockProvider

* Refactor option classes to parameter classes in workflow runtime

This refactoring enhances the clarity of the Elsa Workflow runtime by renaming "options" classes to "parameters" classes. The name "options" misrepresented the classes' role and created confusion, as they are used to parameterize method calls rather than to configure services. The change applies to various workflow methods and tests across the project.
This commit is contained in:
Sipke Schoorstra 2024-02-22 19:37:03 +01:00 committed by GitHub
parent 2710d6e7af
commit 5f47cd0aab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
82 changed files with 193 additions and 191 deletions

View file

@ -3,6 +3,7 @@ using Elsa.Workflows.Activities;
using Elsa.Workflows.Models;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
namespace Elsa.Server.Web.Endpoints.DynamicWorkflows.Post;
@ -31,6 +32,6 @@ public class Post(IWorkflowRegistry workflowRegistry, IWorkflowRuntime workflowR
};
await workflowRegistry.RegisterAsync(workflow, ct);
await workflowRuntime.StartWorkflowAsync("DynamicWorkflow1", new StartWorkflowRuntimeOptions());
await workflowRuntime.StartWorkflowAsync("DynamicWorkflow1", new StartWorkflowRuntimeParams());
}
}

View file

@ -8,6 +8,7 @@ using Elsa.Workflows.Models;
using Elsa.Workflows.Options;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.State;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
@ -66,7 +67,7 @@ public static class ServiceProviderExtensions
IDictionary<string, object>? input = default,
VersionOptions? versionOptions = default)
{
var startWorkflowOptions = new StartWorkflowRuntimeOptions
var startWorkflowOptions = new StartWorkflowRuntimeParams
{
Input = input,
VersionOptions = versionOptions ?? VersionOptions.Published
@ -78,7 +79,7 @@ public static class ServiceProviderExtensions
// Continue resuming the workflow for as long as there are bookmarks to resume and the workflow is not Finished.
while (result.Status != WorkflowStatus.Finished && bookmarks.TryPop(out var bookmark))
{
var resumeOptions = new ResumeWorkflowRuntimeOptions { BookmarkId = bookmark.Id };
var resumeOptions = new ResumeWorkflowRuntimeParams { BookmarkId = bookmark.Id };
var resumeResult = await workflowRuntime.ResumeWorkflowAsync(result.WorkflowInstanceId, resumeOptions);
foreach (var newBookmark in resumeResult!.Bookmarks)

View file

@ -24,6 +24,7 @@ using Elsa.Workflows.Models;
using Elsa.Workflows.Runtime.Filters;
using Elsa.Workflows.Runtime.Matches;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.Runtime.Results;
using Elsa.Workflows.State;
@ -155,7 +156,7 @@ public class WorkflowsMiddleware
{
var httpBookmarkProcessor = serviceProvider.GetRequiredService<IHttpBookmarkProcessor>();
var systemCancellationToken = cancellationTokens.SystemCancellationToken;
var executionOptions = new ExecuteWorkflowOptions
var executionOptions = new ExecuteWorkflowParams
{
Input = input,
CancellationTokens = cancellationTokens

View file

@ -4,7 +4,7 @@ using Elsa.Workflows.Management.Contracts;
using Elsa.Workflows.Management.Mappers;
using Elsa.Workflows.Models;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.Runtime.Results;
using Elsa.Workflows.State;
using Microsoft.AspNetCore.Http;
@ -96,7 +96,7 @@ public class HttpBookmarkProcessor : IHttpBookmarkProcessor
systemCancellationToken);
var workflowHost = await _workflowHostFactory.CreateAsync(workflow, workflowState, applicationCancellationToken);
var options = new ResumeWorkflowHostOptions
var options = new ResumeWorkflowHostParams
{
CorrelationId = correlationId,
BookmarkId = result.BookmarkId,

View file

@ -1,6 +1,7 @@
using Elsa.MassTransit.Messages;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using JetBrains.Annotations;
using MassTransit;
@ -31,7 +32,7 @@ public class DispatchWorkflowRequestConsumer :
{
var message = context.Message;
var cancellationToken = context.CancellationToken;
var options = new StartWorkflowRuntimeOptions
var options = new StartWorkflowRuntimeParams
{
CorrelationId = message.CorrelationId,
Input = message.Input,
@ -51,7 +52,7 @@ public class DispatchWorkflowRequestConsumer :
var message = context.Message;
var cancellationToken = context.CancellationToken;
var options = new ResumeWorkflowRuntimeOptions
var options = new ResumeWorkflowRuntimeParams
{
CorrelationId = message.CorrelationId,
BookmarkId = message.BookmarkId,

View file

@ -10,6 +10,7 @@ using Elsa.Workflows.Management.Contracts;
using Elsa.Workflows.Management.Mappers;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.Runtime.Requests;
using Elsa.Workflows.State;
using Microsoft.Extensions.DependencyInjection;
@ -110,7 +111,7 @@ internal class WorkflowInstance : WorkflowInstanceBase
var properties = request.Properties?.Deserialize();
var versionOptions = VersionOptions.FromString(request.VersionOptions);
var cancellationToken = Context.CancellationToken;
var startWorkflowOptions = new StartWorkflowHostOptions
var startWorkflowOptions = new StartWorkflowHostParams
{
InstanceId = instanceId,
CorrelationId = correlationId,
@ -161,7 +162,7 @@ internal class WorkflowInstance : WorkflowInstanceBase
_input = input;
}
var startWorkflowOptions = new StartWorkflowHostOptions
var startWorkflowOptions = new StartWorkflowHostParams
{
InstanceId = instanceId,
CorrelationId = correlationId,
@ -252,7 +253,7 @@ internal class WorkflowInstance : WorkflowInstanceBase
_cancellationTokenSources.Add(cancellationTokenSource);
cancellationToken = cancellationTokenSource.Token;
var resumeWorkflowHostOptions = new ResumeWorkflowHostOptions
var resumeWorkflowHostOptions = new ResumeWorkflowHostParams
{
CorrelationId = correlationId,
BookmarkId = bookmarkId,

View file

@ -11,6 +11,7 @@ using Elsa.Workflows.Runtime.Entities;
using Elsa.Workflows.Runtime.Filters;
using Elsa.Workflows.Runtime.Matches;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.Runtime.Results;
using Elsa.Workflows.State;
using Proto.Cluster;
@ -67,7 +68,7 @@ internal class ProtoActorWorkflowRuntime : IWorkflowRuntime
}
/// <inheritdoc />
public async Task<CanStartWorkflowResult> CanStartWorkflowAsync(string definitionId, StartWorkflowRuntimeOptions? options = default)
public async Task<CanStartWorkflowResult> CanStartWorkflowAsync(string definitionId, StartWorkflowRuntimeParams? options = default)
{
var versionOptions = options?.VersionOptions;
var correlationId = options?.CorrelationId;
@ -92,7 +93,7 @@ internal class ProtoActorWorkflowRuntime : IWorkflowRuntime
}
/// <inheritdoc />
public async Task<WorkflowExecutionResult?> TryStartWorkflowAsync(string definitionId, StartWorkflowRuntimeOptions? options = default)
public async Task<WorkflowExecutionResult?> TryStartWorkflowAsync(string definitionId, StartWorkflowRuntimeParams? options = default)
{
// Load the workflow definition.
var versionOptions = options?.VersionOptions ?? VersionOptions.Published;
@ -105,7 +106,7 @@ internal class ProtoActorWorkflowRuntime : IWorkflowRuntime
}
/// <inheritdoc />
public async Task<WorkflowExecutionResult> StartWorkflowAsync(string definitionId, StartWorkflowRuntimeOptions? options = default)
public async Task<WorkflowExecutionResult> StartWorkflowAsync(string definitionId, StartWorkflowRuntimeParams? options = default)
{
var versionOptions = options?.VersionOptions;
var correlationId = options?.CorrelationId;
@ -142,7 +143,7 @@ internal class ProtoActorWorkflowRuntime : IWorkflowRuntime
{
var definitionId = trigger.WorkflowDefinitionId;
var startOptions = new StartWorkflowRuntimeOptions
var startOptions = new StartWorkflowRuntimeParams
{
CorrelationId = options?.CorrelationId,
Input = options?.Input,
@ -167,7 +168,7 @@ internal class ProtoActorWorkflowRuntime : IWorkflowRuntime
}
/// <inheritdoc />
public async Task<WorkflowExecutionResult?> ResumeWorkflowAsync(string workflowInstanceId, ResumeWorkflowRuntimeOptions? options = default)
public async Task<WorkflowExecutionResult?> ResumeWorkflowAsync(string workflowInstanceId, ResumeWorkflowRuntimeParams? options = default)
{
var request = new ResumeWorkflowRequest
{
@ -196,7 +197,7 @@ internal class ProtoActorWorkflowRuntime : IWorkflowRuntime
return await ResumeWorkflowsAsync(
bookmarks,
new ResumeWorkflowRuntimeOptions
new ResumeWorkflowRuntimeParams
{
CorrelationId = correlationId,
Input = options?.Input,
@ -217,11 +218,11 @@ internal class ProtoActorWorkflowRuntime : IWorkflowRuntime
}
/// <inheritdoc />
public async Task<WorkflowExecutionResult> ExecuteWorkflowAsync(WorkflowMatch match, ExecuteWorkflowOptions? options = default)
public async Task<WorkflowExecutionResult> ExecuteWorkflowAsync(WorkflowMatch match, ExecuteWorkflowParams? options = default)
{
if (match is StartableWorkflowMatch collectedStartableWorkflow)
{
var startOptions = new StartWorkflowRuntimeOptions
var startOptions = new StartWorkflowRuntimeParams
{
CorrelationId = collectedStartableWorkflow.CorrelationId,
Input = options?.Input,
@ -235,7 +236,7 @@ internal class ProtoActorWorkflowRuntime : IWorkflowRuntime
}
var collectedResumableWorkflow = (match as ResumableWorkflowMatch)!;
var runtimeOptions = new ResumeWorkflowRuntimeOptions
var runtimeOptions = new ResumeWorkflowRuntimeParams
{
CorrelationId = collectedResumableWorkflow.CorrelationId,
Input = options?.Input,
@ -310,7 +311,7 @@ internal class ProtoActorWorkflowRuntime : IWorkflowRuntime
return await _workflowInstanceStore.CountAsync(filter, cancellationToken);
}
private async Task<ICollection<WorkflowExecutionResult>> ResumeWorkflowsAsync(IEnumerable<StoredBookmark> bookmarks, ResumeWorkflowRuntimeOptions runtimeOptions)
private async Task<ICollection<WorkflowExecutionResult>> ResumeWorkflowsAsync(IEnumerable<StoredBookmark> bookmarks, ResumeWorkflowRuntimeParams runtimeParams)
{
var resumedWorkflows = new List<WorkflowExecutionResult>();
@ -318,17 +319,17 @@ internal class ProtoActorWorkflowRuntime : IWorkflowRuntime
{
var workflowInstanceId = bookmark.WorkflowInstanceId;
var newRuntimeOptions = new ResumeWorkflowRuntimeOptions
var newRuntimeOptions = new ResumeWorkflowRuntimeParams
{
CorrelationId = runtimeOptions.CorrelationId,
Input = runtimeOptions.Input,
Properties = runtimeOptions.Properties,
CorrelationId = runtimeParams.CorrelationId,
Input = runtimeParams.Input,
Properties = runtimeParams.Properties,
BookmarkId = bookmark.BookmarkId,
ActivityId = runtimeOptions.ActivityId,
ActivityNodeId = runtimeOptions.ActivityNodeId,
ActivityInstanceId = runtimeOptions.ActivityInstanceId,
ActivityHash = runtimeOptions.ActivityHash,
CancellationTokens = runtimeOptions.CancellationTokens
ActivityId = runtimeParams.ActivityId,
ActivityNodeId = runtimeParams.ActivityNodeId,
ActivityInstanceId = runtimeParams.ActivityInstanceId,
ActivityHash = runtimeParams.ActivityHash,
CancellationTokens = runtimeParams.CancellationTokens
};
var resumeResult = await ResumeWorkflowAsync(workflowInstanceId, newRuntimeOptions);
@ -349,7 +350,7 @@ internal class ProtoActorWorkflowRuntime : IWorkflowRuntime
{
var definitionId = trigger.WorkflowDefinitionId;
var startOptions = new StartWorkflowRuntimeOptions
var startOptions = new StartWorkflowRuntimeParams
{
CorrelationId = workflowsFilter.Options.CorrelationId,
Input = workflowsFilter.Options.Input,

View file

@ -7,6 +7,7 @@ using Elsa.Workflows.Management.Contracts;
using Elsa.Workflows.Management.Filters;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.State;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Http;
@ -64,7 +65,7 @@ internal class Execute : ElsaEndpoint<Request, Response>
var correlationId = request.CorrelationId;
var input = (IDictionary<string, object>?)request.Input;
var instanceId = _identityGenerator.GenerateId();
var startWorkflowOptions = new StartWorkflowRuntimeOptions
var startWorkflowOptions = new StartWorkflowRuntimeParams
{
CorrelationId = correlationId,
Input = input,

View file

@ -1,5 +1,5 @@
using Elsa.Workflows.Activities;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.Runtime.Results;
using Elsa.Workflows.State;
@ -23,15 +23,15 @@ public interface IWorkflowHost
/// <summary>
/// Returns a value indicating whether or not the specified workflow can start a new instance or not.
/// </summary>
Task<bool> CanStartWorkflowAsync(StartWorkflowHostOptions? options = default, CancellationToken cancellationToken = default);
Task<bool> CanStartWorkflowAsync(StartWorkflowHostParams? @params = default, CancellationToken cancellationToken = default);
/// <summary>
/// Start a new workflow instance and execute it.
/// </summary>
Task<StartWorkflowHostResult> StartWorkflowAsync(StartWorkflowHostOptions? options = default, CancellationToken cancellationToken = default);
Task<StartWorkflowHostResult> StartWorkflowAsync(StartWorkflowHostParams? @params = default, CancellationToken cancellationToken = default);
/// <summary>
/// Resume an existing workflow instance.
/// </summary>
Task<ResumeWorkflowHostResult> ResumeWorkflowAsync(ResumeWorkflowHostOptions? options = default, CancellationToken cancellationToken = default);
Task<ResumeWorkflowHostResult> ResumeWorkflowAsync(ResumeWorkflowHostParams? @params = default, CancellationToken cancellationToken = default);
}

View file

@ -1,7 +1,7 @@
using Elsa.Workflows.Runtime.Entities;
using Elsa.Workflows.Runtime.Filters;
using Elsa.Workflows.Runtime.Models;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.Runtime.Results;
namespace Elsa.Workflows.Runtime.Contracts;
@ -24,7 +24,7 @@ public interface IWorkflowInbox
/// <param name="message">The message to store.</param>
/// <param name="options">An optional set of delivery options.</param>
/// <param name="cancellationToken">An optional cancellation token.</param>
ValueTask<SubmitWorkflowInboxMessageResult> SubmitAsync(NewWorkflowInboxMessage message, WorkflowInboxMessageDeliveryOptions options, CancellationToken cancellationToken = default);
ValueTask<SubmitWorkflowInboxMessageResult> SubmitAsync(NewWorkflowInboxMessage message, WorkflowInboxMessageDeliveryParams options, CancellationToken cancellationToken = default);
/// <summary>
/// Delivers a message to a workflow instance.

View file

@ -2,6 +2,7 @@ using Elsa.Workflows.Runtime.Entities;
using Elsa.Workflows.Runtime.Filters;
using Elsa.Workflows.Runtime.Matches;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.Runtime.Requests;
using Elsa.Workflows.Runtime.Results;
using Elsa.Workflows.State;
@ -16,14 +17,14 @@ public interface IWorkflowRuntime
/// <summary>
/// Returns a value whether or not the specified workflow definition can create a new instance.
/// </summary>
Task<CanStartWorkflowResult> CanStartWorkflowAsync(string definitionId, StartWorkflowRuntimeOptions? options = default);
Task<CanStartWorkflowResult> CanStartWorkflowAsync(string definitionId, StartWorkflowRuntimeParams? options = default);
/// <summary>
/// Creates a new workflow instance of the specified definition ID and executes it.
/// </summary>
/// <param name="definitionId">The workflow definition ID to run.</param>
/// <param name="options">Options for starting the workflow.</param>
Task<WorkflowExecutionResult> StartWorkflowAsync(string definitionId, StartWorkflowRuntimeOptions? options = default);
Task<WorkflowExecutionResult> StartWorkflowAsync(string definitionId, StartWorkflowRuntimeParams? options = default);
/// <summary>
/// Starts all workflows with triggers matching the specified activity type and bookmark payload.
@ -34,14 +35,14 @@ public interface IWorkflowRuntime
/// <summary>
/// Tries to start a workflow and returns the result if successful.
/// </summary>
Task<WorkflowExecutionResult?> TryStartWorkflowAsync(string definitionId, StartWorkflowRuntimeOptions? options = default);
Task<WorkflowExecutionResult?> TryStartWorkflowAsync(string definitionId, StartWorkflowRuntimeParams? options = default);
/// <summary>
/// Resumes an existing workflow instance.
/// </summary>
/// <param name="workflowInstanceId">The ID of the workflow instance to resume.</param>
/// <param name="options">Options for resuming the workflow.</param>
Task<WorkflowExecutionResult?> ResumeWorkflowAsync(string workflowInstanceId, ResumeWorkflowRuntimeOptions? options = default);
Task<WorkflowExecutionResult?> ResumeWorkflowAsync(string workflowInstanceId, ResumeWorkflowRuntimeParams? options = default);
/// <summary>
/// Resumes all workflows that are bookmarked on the specified activity type.
@ -58,7 +59,7 @@ public interface IWorkflowRuntime
/// </summary>
/// <param name="match">A workflow match to execute.</param>
/// <param name="options">Options for executing the workflow.</param>
Task<WorkflowExecutionResult> ExecuteWorkflowAsync(WorkflowMatch match, ExecuteWorkflowOptions? options = default);
Task<WorkflowExecutionResult> ExecuteWorkflowAsync(WorkflowMatch match, ExecuteWorkflowParams? options = default);
/// <summary>
/// Cancels the execution of a workflow.

View file

@ -3,6 +3,7 @@ using Elsa.Mediator.Models;
using Elsa.Workflows.Runtime.Commands;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
namespace Elsa.Workflows.Runtime.Handlers;
@ -31,7 +32,7 @@ internal class DispatchWorkflowCommandHandler(IWorkflowRuntime workflowRuntime)
public async Task<Unit> HandleAsync(DispatchWorkflowDefinitionCommand command, CancellationToken cancellationToken)
{
var options = new StartWorkflowRuntimeOptions
var options = new StartWorkflowRuntimeParams
{
CorrelationId = command.CorrelationId,
Input = command.Input,
@ -49,7 +50,7 @@ internal class DispatchWorkflowCommandHandler(IWorkflowRuntime workflowRuntime)
public async Task<Unit> HandleAsync(DispatchWorkflowInstanceCommand command, CancellationToken cancellationToken)
{
var options = new ResumeWorkflowRuntimeOptions
var options = new ResumeWorkflowRuntimeParams
{
CorrelationId = command.CorrelationId,
BookmarkId = command.BookmarkId,

View file

@ -1,31 +1,43 @@
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Options;
using JetBrains.Annotations;
using Medallion.Threading;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
namespace Elsa.Workflows.Runtime.HostedServices;
/// <summary>
/// Updates the workflow store from <see cref="IWorkflowProvider"/> implementations, creates triggers and updates the <see cref="IActivityRegistry"/>.
/// </summary>
[UsedImplicitly]
public class PopulateRegistriesHostedService : IHostedService
{
private readonly IServiceScopeFactory _scopeFactory;
private readonly DistributedLockingOptions _options;
/// <summary>
/// Initializes a new instance of the <see cref="PopulateRegistriesHostedService"/> class.
/// </summary>
public PopulateRegistriesHostedService(IServiceScopeFactory scopeFactory)
public PopulateRegistriesHostedService(IServiceScopeFactory scopeFactory, IOptions<DistributedLockingOptions> options)
{
_scopeFactory = scopeFactory;
_options = options.Value;
}
/// <inheritdoc />
public async Task StartAsync(CancellationToken cancellationToken)
{
using var scope = _scopeFactory.CreateScope();
var registriesPopulator = scope.ServiceProvider.GetRequiredService<IRegistriesPopulator>();
await registriesPopulator.PopulateAsync(cancellationToken);
var distributedLockProvider = scope.ServiceProvider.GetRequiredService<IDistributedLockProvider>();
var lockAcquisitionTimeout = _options.LockAcquisitionTimeout;
await using (await distributedLockProvider.AcquireLockAsync("PopulateRegistries", lockAcquisitionTimeout, cancellationToken))
{
var registriesPopulator = scope.ServiceProvider.GetRequiredService<IRegistriesPopulator>();
await registriesPopulator.PopulateAsync(cancellationToken);
}
}
/// <inheritdoc />

View file

@ -1,6 +1,7 @@
using Elsa.Mediator.Contracts;
using Elsa.Workflows.Runtime.Entities;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.Runtime.Results;
namespace Elsa.Workflows.Runtime.Notifications;
@ -11,5 +12,5 @@ namespace Elsa.Workflows.Runtime.Notifications;
/// <param name="InboxMessage">The inbox message that was received.</param>
public record WorkflowInboxMessageReceived(
WorkflowInboxMessage InboxMessage,
WorkflowInboxMessageDeliveryOptions Options,
WorkflowInboxMessageDeliveryParams Options,
ICollection<WorkflowExecutionResult> WorkflowExecutionResults) : INotification;

View file

@ -1,10 +1,12 @@
using Elsa.Workflows.Runtime.Services;
using JetBrains.Annotations;
namespace Elsa.Workflows.Runtime.Options;
/// <summary>
/// Provides options related to distributed locking, which is used by <see cref="DefaultWorkflowRuntime"/>.
/// </summary>
[UsedImplicitly]
public class DistributedLockingOptions
{
/// <summary>

View file

@ -1,11 +1,11 @@
using Elsa.Workflows.Models;
namespace Elsa.Workflows.Runtime.Options;
namespace Elsa.Workflows.Runtime.Parameters;
/// <summary>
/// Options for executing workflows.
/// </summary>
public class ExecuteWorkflowOptions
public class ExecuteWorkflowParams
{
public IDictionary<string, object>? Input { get; set; }
public IDictionary<string, object>? Properties { get; set; }

View file

@ -1,11 +1,11 @@
using Elsa.Workflows.Models;
namespace Elsa.Workflows.Runtime.Options;
namespace Elsa.Workflows.Runtime.Parameters;
/// <summary>
/// Represents options for resuming a workflow host.
/// </summary>
public class ResumeWorkflowHostOptions
public class ResumeWorkflowHostParams
{
/// <summary>An optional correlation ID.</summary>
public string? CorrelationId { get; set; }

View file

@ -1,11 +1,11 @@
using Elsa.Workflows.Models;
namespace Elsa.Workflows.Runtime.Options;
namespace Elsa.Workflows.Runtime.Parameters;
/// <summary>
/// Options for resuming workflows.
/// </summary>
public class ResumeWorkflowRuntimeOptions
public class ResumeWorkflowRuntimeParams
{
public string? CorrelationId { get; set; }
public string? BookmarkId { get; set; }

View file

@ -1,11 +1,11 @@
using Elsa.Workflows.Models;
namespace Elsa.Workflows.Runtime.Options;
namespace Elsa.Workflows.Runtime.Parameters;
/// <summary>
/// Represents options for starting a workflow host.
/// </summary>
public class StartWorkflowHostOptions
public class StartWorkflowHostParams
{
/// <summary>An optional workflow instance ID. If not specified, a new ID will be generated.</summary>
public string? InstanceId { get; set; }

View file

@ -1,12 +1,12 @@
using Elsa.Common.Models;
using Elsa.Workflows.Models;
namespace Elsa.Workflows.Runtime.Options;
namespace Elsa.Workflows.Runtime.Parameters;
/// <summary>
/// Represents options for starting a workflow.
/// </summary>
public class StartWorkflowRuntimeOptions
public class StartWorkflowRuntimeParams
{
public string? CorrelationId { get; set; }

View file

@ -1,9 +1,9 @@
namespace Elsa.Workflows.Runtime.Options;
namespace Elsa.Workflows.Runtime.Parameters;
/// <summary>
/// Options for delivering a workflow inbox message.
/// </summary>
public class WorkflowInboxMessageDeliveryOptions
public class WorkflowInboxMessageDeliveryParams
{
/// <summary>
/// Whether to dispatch the message to the workflow dispatcher or send immediately.

View file

@ -21,6 +21,7 @@ public class DefaultWorkflowDefinitionStorePopulator : IWorkflowDefinitionStoreP
private readonly IPayloadSerializer _payloadSerializer;
private readonly ISystemClock _systemClock;
private readonly IIdentityGraphService _identityGraphService;
private readonly SemaphoreSlim _semaphore = new(1, 1);
/// <summary>
/// Constructor.
@ -51,13 +52,10 @@ public class DefaultWorkflowDefinitionStorePopulator : IWorkflowDefinitionStoreP
{
var results = await provider.GetWorkflowsAsync(cancellationToken).AsTask().ToList();
foreach (var result in results)
{
await AddAsync(result, cancellationToken);
}
foreach (var result in results) await AddAsync(result, cancellationToken);
}
}
/// <inheritdoc />
public async Task AddAsync(MaterializedWorkflow materializedWorkflow, CancellationToken cancellationToken = default)
{
@ -72,6 +70,20 @@ public class DefaultWorkflowDefinitionStorePopulator : IWorkflowDefinitionStoreP
}
private async Task AddOrUpdateAsync(MaterializedWorkflow materializedWorkflow, CancellationToken cancellationToken = default)
{
await _semaphore.WaitAsync(cancellationToken);
try
{
await AddOrUpdateCoreAsync(materializedWorkflow, cancellationToken);
}
finally
{
_semaphore.Release();
}
}
private async Task AddOrUpdateCoreAsync(MaterializedWorkflow materializedWorkflow, CancellationToken cancellationToken = default)
{
var workflow = materializedWorkflow.Workflow;
var definitionId = workflow.Identity.DefinitionId;
@ -89,25 +101,29 @@ public class DefaultWorkflowDefinitionStorePopulator : IWorkflowDefinitionStoreP
DefinitionId = definitionId,
VersionOptions = VersionOptions.SpecificVersion(workflow.Identity.Version)
};
var existingDefinitionVersion = await _workflowDefinitionStore.FindAsync(specificVersionFilter, cancellationToken);
// Setup a list to collect all workflow definitions to be persisted.
var workflowDefinitionsToSave = new HashSet<WorkflowDefinition>();
if(existingDefinitionVersion != null)
if (existingDefinitionVersion != null)
workflowDefinitionsToSave.Add(existingDefinitionVersion);
// If the workflow being added is configured to be the latest version, then we need to reset the current latest version.
if (workflow.Publication.IsLatest)
{
// Reset current latest definitions.
var filter = new WorkflowDefinitionFilter { DefinitionId = definitionId, VersionOptions = VersionOptions.Latest };
var filter = new WorkflowDefinitionFilter
{
DefinitionId = definitionId,
VersionOptions = VersionOptions.Latest
};
var latestWorkflowDefinitions = (await _workflowDefinitionStore.FindManyAsync(filter, cancellationToken)).ToList();
// If the latest definitions contains definitions with the same ID then we need to replace them with the latest workflow definitions.
SyncExistingCopies(latestWorkflowDefinitions, workflowDefinitionsToSave);
foreach (var latestWorkflowDefinition in latestWorkflowDefinitions)
{
latestWorkflowDefinition.IsLatest = false;
@ -119,12 +135,16 @@ public class DefaultWorkflowDefinitionStorePopulator : IWorkflowDefinitionStoreP
if (workflow.Publication.IsPublished)
{
// Reset current published definitions.
var filter = new WorkflowDefinitionFilter { DefinitionId = definitionId, VersionOptions = VersionOptions.Published };
var filter = new WorkflowDefinitionFilter
{
DefinitionId = definitionId,
VersionOptions = VersionOptions.Published
};
var publishedWorkflowDefinitions = (await _workflowDefinitionStore.FindManyAsync(filter, cancellationToken)).ToList();
// If the published workflow definitions contains definitions with the same ID as definitions in the latest workflow definitions, then we need to replace them with the latest workflow definitions.
SyncExistingCopies(publishedWorkflowDefinitions, workflowDefinitionsToSave);
foreach (var publishedWorkflowDefinition in publishedWorkflowDefinitions)
{
publishedWorkflowDefinition.IsPublished = false;
@ -138,7 +158,7 @@ public class DefaultWorkflowDefinitionStorePopulator : IWorkflowDefinitionStoreP
Id = workflow.Identity.Id,
Version = workflow.Identity.Version
};
workflowDefinition.Description = workflow.WorkflowMetadata.Description;
workflowDefinition.Name = workflow.WorkflowMetadata.Name;
workflowDefinition.ToolVersion = workflow.WorkflowMetadata.ToolVersion;
@ -171,6 +191,6 @@ public class DefaultWorkflowDefinitionStorePopulator : IWorkflowDefinitionStoreP
var ids = secondary.Select(x => x.Id).Distinct().ToList();
var latestWorkflowDefinitions = primary.Where(x => ids.Contains(x.Id)).ToList();
primary.RemoveAll(x => latestWorkflowDefinitions.Contains(x));
primary.AddRange(secondary.Where(x => ids.Contains(x.Id)));
primary.AddRange(secondary.Where(x => ids.Contains(x.Id)));
}
}

View file

@ -8,6 +8,7 @@ using Elsa.Workflows.Runtime.Filters;
using Elsa.Workflows.Runtime.Models;
using Elsa.Workflows.Runtime.Notifications;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.Runtime.Requests;
using Elsa.Workflows.Runtime.Results;
@ -48,12 +49,12 @@ public class DefaultWorkflowInbox : IWorkflowInbox
/// <inheritdoc />
public async ValueTask<SubmitWorkflowInboxMessageResult> SubmitAsync(NewWorkflowInboxMessage message, CancellationToken cancellationToken = default)
{
var defaultOptions = new WorkflowInboxMessageDeliveryOptions();
var defaultOptions = new WorkflowInboxMessageDeliveryParams();
return await SubmitAsync(message, defaultOptions, cancellationToken);
}
/// <inheritdoc />
public async ValueTask<SubmitWorkflowInboxMessageResult> SubmitAsync(NewWorkflowInboxMessage newMessage, WorkflowInboxMessageDeliveryOptions options, CancellationToken cancellationToken = default)
public async ValueTask<SubmitWorkflowInboxMessageResult> SubmitAsync(NewWorkflowInboxMessage newMessage, WorkflowInboxMessageDeliveryParams @params, CancellationToken cancellationToken = default)
{
var now = _systemClock.UtcNow;
@ -77,7 +78,7 @@ public class DefaultWorkflowInbox : IWorkflowInbox
// Send a notification.
var workflowExecutionResults = new List<WorkflowExecutionResult>();
var notification = new WorkflowInboxMessageReceived(message, options, workflowExecutionResults);
var notification = new WorkflowInboxMessageReceived(message, @params, workflowExecutionResults);
await _notificationSender.SendAsync(notification, NotificationStrategy.Sequential, cancellationToken);
// Return the result.

View file

@ -10,6 +10,7 @@ using Elsa.Workflows.Runtime.Entities;
using Elsa.Workflows.Runtime.Filters;
using Elsa.Workflows.Runtime.Matches;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.Runtime.Requests;
using Elsa.Workflows.Runtime.Results;
using Elsa.Workflows.State;
@ -73,12 +74,12 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
}
/// <inheritdoc />
public async Task<CanStartWorkflowResult> CanStartWorkflowAsync(string definitionId, StartWorkflowRuntimeOptions? options = default)
public async Task<CanStartWorkflowResult> CanStartWorkflowAsync(string definitionId, StartWorkflowRuntimeParams? options = default)
{
var input = options?.Input;
var correlationId = options?.CorrelationId;
var workflowHost = await CreateWorkflowHostAsync(definitionId, options, options?.CancellationTokens.SystemCancellationToken ?? default);
var startWorkflowOptions = new StartWorkflowHostOptions
var startWorkflowOptions = new StartWorkflowHostParams
{
CorrelationId = correlationId,
Input = input,
@ -89,14 +90,14 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
}
/// <inheritdoc />
public async Task<WorkflowExecutionResult> StartWorkflowAsync(string definitionId, StartWorkflowRuntimeOptions? options = default)
public async Task<WorkflowExecutionResult> StartWorkflowAsync(string definitionId, StartWorkflowRuntimeParams? options = default)
{
var workflowHost = await CreateWorkflowHostAsync(definitionId, options, options?.CancellationTokens.SystemCancellationToken ?? default);
return await StartWorkflowAsync(workflowHost, options);
}
/// <inheritdoc />
public async Task<WorkflowExecutionResult?> TryStartWorkflowAsync(string definitionId, StartWorkflowRuntimeOptions? options = default)
public async Task<WorkflowExecutionResult?> TryStartWorkflowAsync(string definitionId, StartWorkflowRuntimeParams? options = default)
{
return await StartWorkflowAsync(definitionId, options);
}
@ -184,7 +185,7 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
{
var definitionId = trigger.WorkflowDefinitionId;
var startOptions = new StartWorkflowRuntimeOptions
var startOptions = new StartWorkflowRuntimeParams
{
CorrelationId = options.CorrelationId,
Input = options.Input,
@ -213,7 +214,7 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
}
/// <inheritdoc />
public async Task<WorkflowExecutionResult?> ResumeWorkflowAsync(string workflowInstanceId, ResumeWorkflowRuntimeOptions? options = default)
public async Task<WorkflowExecutionResult?> ResumeWorkflowAsync(string workflowInstanceId, ResumeWorkflowRuntimeParams? options = default)
{
var applicationCancellationToken = options?.CancellationTokens.ApplicationCancellationToken ?? default;
var systemCancellationToken = options?.CancellationTokens.SystemCancellationToken ?? default;
@ -245,7 +246,7 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
var workflowState = _workflowStateMapper.Map(workflowInstance)!;
var workflowHost = await _workflowHostFactory.CreateAsync(workflow, workflowState, systemCancellationToken);
var resumeWorkflowOptions = new ResumeWorkflowHostOptions
var resumeWorkflowOptions = new ResumeWorkflowHostParams
{
CorrelationId = options?.CorrelationId,
BookmarkId = options?.BookmarkId,
@ -286,7 +287,7 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
return await ResumeWorkflowsAsync(
bookmarks,
new ResumeWorkflowRuntimeOptions
new ResumeWorkflowRuntimeParams
{
CorrelationId = correlationId,
Input = options.Input,
@ -304,11 +305,11 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
}
/// <inheritdoc />
public async Task<WorkflowExecutionResult> ExecuteWorkflowAsync(WorkflowMatch match, ExecuteWorkflowOptions? options = default)
public async Task<WorkflowExecutionResult> ExecuteWorkflowAsync(WorkflowMatch match, ExecuteWorkflowParams? options = default)
{
if (match is StartableWorkflowMatch collectedStartableWorkflow)
{
var startOptions = new StartWorkflowRuntimeOptions
var startOptions = new StartWorkflowRuntimeParams
{
CorrelationId = collectedStartableWorkflow.CorrelationId,
Input = options?.Input,
@ -327,7 +328,7 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
}
var collectedResumableWorkflow = (match as ResumableWorkflowMatch)!;
var runtimeOptions = new ResumeWorkflowRuntimeOptions
var runtimeOptions = new ResumeWorkflowRuntimeParams
{
CorrelationId = collectedResumableWorkflow.CorrelationId,
BookmarkId = collectedResumableWorkflow.BookmarkId,
@ -381,7 +382,7 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
return await _workflowInstanceStore.CountAsync(filter, cancellationToken);
}
private async Task<WorkflowExecutionResult> StartWorkflowAsync(IWorkflowHost workflowHost, StartWorkflowRuntimeOptions? options = default)
private async Task<WorkflowExecutionResult> StartWorkflowAsync(IWorkflowHost workflowHost, StartWorkflowRuntimeParams? options = default)
{
var workflowInstanceId = string.IsNullOrEmpty(options?.InstanceId) ? _identityGenerator.GenerateId() : options?.InstanceId;
var cancellationTokens = options?.CancellationTokens ?? default;
@ -390,7 +391,7 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
{
var input = options?.Input;
var correlationId = options?.CorrelationId;
var startWorkflowOptions = new StartWorkflowHostOptions
var startWorkflowOptions = new StartWorkflowHostParams
{
InstanceId = workflowInstanceId,
CorrelationId = correlationId,
@ -414,7 +415,7 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
}
}
private async Task<IWorkflowHost> CreateWorkflowHostAsync(string definitionId, StartWorkflowRuntimeOptions? options, CancellationToken cancellationToken)
private async Task<IWorkflowHost> CreateWorkflowHostAsync(string definitionId, StartWorkflowRuntimeParams? options, CancellationToken cancellationToken)
{
var versionOptions = options?.VersionOptions;
var host = await _workflowHostFactory.CreateAsync(definitionId, versionOptions ?? VersionOptions.Published, cancellationToken);
@ -425,7 +426,7 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
return host;
}
private async Task<ICollection<WorkflowExecutionResult>> ResumeWorkflowsAsync(IEnumerable<StoredBookmark> bookmarks, ResumeWorkflowRuntimeOptions runtimeOptions)
private async Task<ICollection<WorkflowExecutionResult>> ResumeWorkflowsAsync(IEnumerable<StoredBookmark> bookmarks, ResumeWorkflowRuntimeParams runtimeParams)
{
var resumedWorkflows = new List<WorkflowExecutionResult>();
@ -435,12 +436,12 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
var resumeResult = await ResumeWorkflowAsync(
workflowInstanceId,
new ResumeWorkflowRuntimeOptions
new ResumeWorkflowRuntimeParams
{
CorrelationId = runtimeOptions.CorrelationId,
Input = runtimeOptions.Input,
Properties = runtimeOptions.Properties,
CancellationTokens = runtimeOptions.CancellationTokens,
CorrelationId = runtimeParams.CorrelationId,
Input = runtimeParams.Input,
Properties = runtimeParams.Properties,
CancellationTokens = runtimeParams.CancellationTokens,
BookmarkId = bookmark.BookmarkId,
ActivityInstanceId = bookmark.ActivityInstanceId
});
@ -475,7 +476,7 @@ public class DefaultWorkflowRuntime : IWorkflowRuntime
foreach (var trigger in triggers)
{
var definitionId = trigger.WorkflowDefinitionId;
var startOptions = new StartWorkflowRuntimeOptions
var startOptions = new StartWorkflowRuntimeParams
{
CorrelationId = workflowsFilter.Options.CorrelationId,
Input = workflowsFilter.Options.Input,

View file

@ -5,6 +5,7 @@ using Elsa.Workflows.Runtime.Bookmarks;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Models;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.Runtime.Results;
namespace Elsa.Workflows.Runtime.Services;
@ -61,7 +62,7 @@ public class EventPublisher : IEventPublisher
[Event.EventPayloadWorkflowInputKey] = payload ?? new Dictionary<string, object>()
};
var message = NewWorkflowInboxMessage.For<Event>(eventBookmark, workflowInstanceId, correlationId, activityInstanceId, workflowInput);
var options = new WorkflowInboxMessageDeliveryOptions
var options = new WorkflowInboxMessageDeliveryParams
{
DispatchAsynchronously = dispatchAsynchronously
};

View file

@ -5,6 +5,7 @@ using Elsa.Workflows.Models;
using Elsa.Workflows.Options;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Elsa.Workflows.Runtime.Results;
using Elsa.Workflows.State;
using Microsoft.Extensions.DependencyInjection;
@ -45,7 +46,7 @@ public class WorkflowHost : IWorkflowHost
public WorkflowState WorkflowState { get; set; }
/// <inheritdoc />
public async Task<bool> CanStartWorkflowAsync(StartWorkflowHostOptions? options = default, CancellationToken cancellationToken = default)
public async Task<bool> CanStartWorkflowAsync(StartWorkflowHostParams? @params = default, CancellationToken cancellationToken = default)
{
var strategyType = Workflow.Options.ActivationStrategyType;
@ -59,19 +60,19 @@ public class WorkflowHost : IWorkflowHost
if (strategy == null)
return true;
var correlationId = options?.CorrelationId;
var correlationId = @params?.CorrelationId;
var strategyContext = new WorkflowInstantiationStrategyContext(Workflow, correlationId, cancellationToken);
return await strategy.GetAllowActivationAsync(strategyContext);
}
/// <inheritdoc />
public async Task<StartWorkflowHostResult> StartWorkflowAsync(StartWorkflowHostOptions? options = default, CancellationToken cancellationToken = default)
public async Task<StartWorkflowHostResult> StartWorkflowAsync(StartWorkflowHostParams? @params = default, CancellationToken cancellationToken = default)
{
var correlationId = options?.CorrelationId;
var instanceId = options?.InstanceId ?? _identityGenerator.GenerateId();
var correlationId = @params?.CorrelationId;
var instanceId = @params?.InstanceId ?? _identityGenerator.GenerateId();
var originalBookmarks = WorkflowState.Bookmarks.ToList();
var input = options?.Input;
var properties = options?.Properties;
var input = @params?.Input;
var properties = @params?.Properties;
var runOptions = new RunWorkflowOptions
{
@ -79,9 +80,9 @@ public class WorkflowHost : IWorkflowHost
CorrelationId = correlationId,
Input = input,
Properties = properties,
TriggerActivityId = options?.TriggerActivityId,
StatusUpdatedCallback = options?.StatusUpdatedCallback,
CancellationTokens = options?.CancellationTokens ?? cancellationToken
TriggerActivityId = @params?.TriggerActivityId,
StatusUpdatedCallback = @params?.StatusUpdatedCallback,
CancellationTokens = @params?.CancellationTokens ?? cancellationToken
};
using var scope = _serviceScopeFactory.CreateScope();
@ -99,7 +100,7 @@ public class WorkflowHost : IWorkflowHost
/// <summary>
/// Resumes the <see cref="Workflow"/>.
/// </summary>
public async Task<ResumeWorkflowHostResult> ResumeWorkflowAsync(ResumeWorkflowHostOptions? options = default, CancellationToken cancellationToken = default)
public async Task<ResumeWorkflowHostResult> ResumeWorkflowAsync(ResumeWorkflowHostParams? @params = default, CancellationToken cancellationToken = default)
{
var originalBookmarks = WorkflowState.Bookmarks.ToList();
@ -110,20 +111,20 @@ public class WorkflowHost : IWorkflowHost
}
var instanceId = WorkflowState.Id;
var input = options?.Input;
var input = @params?.Input;
var runOptions = new RunWorkflowOptions
{
WorkflowInstanceId = instanceId,
CorrelationId = options?.CorrelationId,
BookmarkId = options?.BookmarkId,
ActivityId = options?.ActivityId,
ActivityNodeId = options?.ActivityNodeId,
ActivityInstanceId = options?.ActivityInstanceId,
ActivityHash = options?.ActivityHash,
CorrelationId = @params?.CorrelationId,
BookmarkId = @params?.BookmarkId,
ActivityId = @params?.ActivityId,
ActivityNodeId = @params?.ActivityNodeId,
ActivityInstanceId = @params?.ActivityInstanceId,
ActivityHash = @params?.ActivityHash,
Input = input,
Properties = options?.Properties,
CancellationTokens = options?.CancellationTokens ?? cancellationToken
Properties = @params?.Properties,
CancellationTokens = @params?.CancellationTokens ?? cancellationToken
};
using var scope = _serviceScopeFactory.CreateScope();

View file

@ -8,6 +8,7 @@
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>

View file

@ -12,6 +12,7 @@ using Elsa.ServiceBus.IntegrationTests.Scenarios.Workflows;
using Elsa.Workflows;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Microsoft.Extensions.Options;
using NSubstitute;
using Xunit.Abstractions;
@ -83,7 +84,7 @@ public class ServiceBusTest : IDisposable
// Start Workflow
const string workflowDefinitionId = nameof(ReceiveMessageWorkflow);
var startWorkflowOptions = new StartWorkflowRuntimeOptions
var startWorkflowOptions = new StartWorkflowRuntimeParams
{
VersionOptions = Common.Models.VersionOptions.Published
};
@ -151,7 +152,7 @@ public class ServiceBusTest : IDisposable
// Start Workflow
const string workflowDefinitionId = nameof(ReceiveOneMessageWorkflow);
var startWorkflowOptions = new StartWorkflowRuntimeOptions { VersionOptions = Common.Models.VersionOptions.Published };
var startWorkflowOptions = new StartWorkflowRuntimeParams { VersionOptions = Common.Models.VersionOptions.Published };
var workflowRuntime = _services.GetRequiredService<IWorkflowRuntime>();
var workflowState = await workflowRuntime.StartWorkflowAsync(workflowDefinitionId, startWorkflowOptions);
@ -222,7 +223,7 @@ public class ServiceBusTest : IDisposable
// Start Workflow
const string workflowDefinitionId = nameof(SendOneMessageWorkflow);
var startWorkflowOptions = new StartWorkflowRuntimeOptions { VersionOptions = Common.Models.VersionOptions.Published };
var startWorkflowOptions = new StartWorkflowRuntimeParams { VersionOptions = Common.Models.VersionOptions.Published };
var workflowRuntime = _services.GetRequiredService<IWorkflowRuntime>();
var workflowState = await workflowRuntime.StartWorkflowAsync(workflowDefinitionId, startWorkflowOptions);
@ -287,7 +288,7 @@ public class ServiceBusTest : IDisposable
//Start Workflow
var workflowDefinitionId = nameof(SendOneMessageWithCorrelationIdWorkflow);
var startWorkflowOptions = new StartWorkflowRuntimeOptions { VersionOptions = Common.Models.VersionOptions.Published };
var startWorkflowOptions = new StartWorkflowRuntimeParams { VersionOptions = Common.Models.VersionOptions.Published };
var workflowRuntime = _services.GetRequiredService<IWorkflowRuntime>();
var workflowState = await workflowRuntime.StartWorkflowAsync(workflowDefinitionId, startWorkflowOptions);
@ -333,7 +334,7 @@ public class ServiceBusTest : IDisposable
// Start Workflow
var workflowDefinitionId = nameof(ReceiveMessageWorkflow);
var startWorkflowOptions = new StartWorkflowRuntimeOptions { VersionOptions = Common.Models.VersionOptions.Published };
var startWorkflowOptions = new StartWorkflowRuntimeParams { VersionOptions = Common.Models.VersionOptions.Published };
var workflowRuntime = _services.GetRequiredService<IWorkflowRuntime>();
var workflowState = await workflowRuntime.StartWorkflowAsync(workflowDefinitionId, startWorkflowOptions);

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Memory;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Memory;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Memory;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Memory;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Runtime.Activities;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;

View file

@ -1,5 +1,4 @@
using Elsa.Testing.Shared;
using Elsa.Workflows;
using Elsa.Workflows.Contracts;
using Microsoft.Extensions.DependencyInjection;
using Xunit;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Memory;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Memory;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Runtime.Activities;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;

View file

@ -1,5 +1,4 @@
using Elsa.Extensions;
using Elsa.Workflows;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Models;

View file

@ -1,5 +1,4 @@
using Elsa.Extensions;
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Memory;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Runtime.Activities;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Memory;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Memory;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Memory;

View file

@ -1,6 +1,5 @@
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.Workflows;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Models;
using Elsa.Workflows.Services;

View file

@ -1,5 +1,4 @@
using Elsa.Extensions;
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.IntegrationTests.Scenarios.CanExecute.Activities;

View file

@ -1,6 +1,5 @@
using Elsa.Extensions;
using Elsa.JavaScript.Activities;
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Memory;

View file

@ -1,5 +1,4 @@
using Elsa.Testing.Shared;
using Elsa.Workflows;
using Xunit;
using Xunit.Abstractions;

View file

@ -1,5 +1,4 @@
using Elsa.Extensions;
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Management.Activities.SetOutput;

View file

@ -1,5 +1,4 @@
using Elsa.Testing.Shared;
using Elsa.Workflows;
using Xunit;
using Xunit.Abstractions;

View file

@ -1,5 +1,4 @@
using Elsa.Testing.Shared;
using Elsa.Workflows;
using Xunit;
using Xunit.Abstractions;

View file

@ -1,5 +1,4 @@
using Elsa.Extensions;
using Elsa.Workflows;
namespace Elsa.Workflows.IntegrationTests.Scenarios.FlowchartNextActivity.Activities;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Activities.Flowchart.Activities;
using Elsa.Workflows.Activities.Flowchart.Models;

View file

@ -1,5 +1,4 @@
using Elsa.Testing.Shared;
using Elsa.Workflows;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.IntegrationTests.Scenarios.ImplicitJoins.Workflows;
using Microsoft.Extensions.DependencyInjection;

View file

@ -1,5 +1,4 @@
using Elsa.Testing.Shared;
using Elsa.Workflows;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.IntegrationTests.Scenarios.ImplicitJoins.Workflows;
using Microsoft.Extensions.DependencyInjection;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Activities.Flowchart.Activities;
using Elsa.Workflows.Activities.Flowchart.Models;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Activities.Flowchart.Activities;
using Elsa.Workflows.Activities.Flowchart.Models;

View file

@ -1,5 +1,4 @@
using Elsa.Testing.Shared;
using Elsa.Workflows;
using Elsa.Workflows.IncidentStrategies;
using Elsa.Workflows.IntegrationTests.Scenarios.Incidents.Statics;
using Elsa.Workflows.IntegrationTests.Scenarios.Incidents.Workflows;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Activities.Flowchart.Activities;
using Elsa.Workflows.Activities.Flowchart.Models;

View file

@ -1,6 +1,5 @@
using System.Text.Json.Nodes;
using Elsa.Extensions;
using Elsa.Workflows;
namespace Elsa.Workflows.IntegrationTests.Scenarios.JsonObjectToObjectRemainsJsonObject.Activities;

View file

@ -1,5 +1,4 @@
using Elsa.Extensions;
using Elsa.Workflows;
using Elsa.Workflows.Models;
namespace Elsa.Workflows.IntegrationTests.Scenarios.JsonObjectToObjectRemainsJsonObject.Activities;

View file

@ -1,7 +1,6 @@
using System.Text.Json.Nodes;
using Elsa.Expressions.Models;
using Elsa.JavaScript.Models;
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.IntegrationTests.Scenarios.JsonObjectToObjectRemainsJsonObject.Activities;

View file

@ -1,5 +1,4 @@
using Elsa.Testing.Shared;
using Elsa.Workflows;
using Xunit;
using Xunit.Abstractions;

View file

@ -1,5 +1,4 @@
using Elsa.Extensions;
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Memory;

View file

@ -1,5 +1,4 @@
using Elsa.Extensions;
using Elsa.Workflows;
namespace Elsa.Workflows.IntegrationTests.Scenarios.SetGetVariablesFromActivities.Activities;

View file

@ -1,5 +1,4 @@
using Elsa.Extensions;
using Elsa.Workflows;
namespace Elsa.Workflows.IntegrationTests.Scenarios.SetGetVariablesFromActivities.Activities;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.IntegrationTests.Scenarios.SetGetVariablesFromActivities.Activities;

View file

@ -1,11 +1,10 @@
using Elsa.Mediator.HostedServices;
using Elsa.Mediator.Options;
using Elsa.Testing.Shared;
using Elsa.Workflows;
using Elsa.Workflows.IntegrationTests.Scenarios.WorkflowCancellation.Workflows;
using Elsa.Workflows.Models;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Xunit;
@ -13,6 +12,9 @@ using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.WorkflowCancellation;
/// <summary>
/// Represents a class containing unit tests for the DefaultRuntime class.
/// </summary>
public class DefaultRuntimeTests
{
private readonly IServiceProvider _services;
@ -22,6 +24,9 @@ public class DefaultRuntimeTests
private readonly BackgroundCommandSenderHostedService _backgroundCommandSenderHostedService;
private readonly BackgroundEventPublisherHostedService _backgroundEventPublisherHostedService;
/// <summary>
/// Initializes a new instance of the <see cref="DefaultRuntimeTests"/> class.
/// </summary>
public DefaultRuntimeTests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper)
@ -59,7 +64,7 @@ public class DefaultRuntimeTests
await _services.PopulateRegistriesAsync();
const string workflowDefinitionId = nameof(SimpleSuspendedWorkflow);
var workflowState = await _workflowRuntime.StartWorkflowAsync(workflowDefinitionId, new StartWorkflowRuntimeOptions());
var workflowState = await _workflowRuntime.StartWorkflowAsync(workflowDefinitionId, new StartWorkflowRuntimeParams());
Assert.Equal(WorkflowStatus.Running, workflowState.Status);
Assert.Equal(WorkflowSubStatus.Suspended, workflowState.SubStatus);
@ -83,10 +88,10 @@ public class DefaultRuntimeTests
await _services.PopulateRegistriesAsync();
const string workflowDefinitionId = nameof(BulkSuspendedWorkflow);
var workflowState = await _workflowRuntime.StartWorkflowAsync(workflowDefinitionId, new StartWorkflowRuntimeOptions());
var workflowState = await _workflowRuntime.StartWorkflowAsync(workflowDefinitionId, new StartWorkflowRuntimeParams());
var bookmarks = new Stack<Bookmark>(workflowState.Bookmarks);
var resumeOptions = new ResumeWorkflowRuntimeOptions
var resumeOptions = new ResumeWorkflowRuntimeParams
{
BookmarkId = bookmarks.Pop().Id
};

View file

@ -6,15 +6,15 @@ using Elsa.Testing.Shared;
using Elsa.Workflows.IntegrationTests.Scenarios.WorkflowCancellation.Workflows;
using Elsa.Workflows.Models;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Parameters;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Proto.Persistence.Sqlite;
using Xunit;
using Xunit.Abstractions;
using WorkflowStatus = Elsa.Workflows.WorkflowStatus;
using WorkflowSubStatus = Elsa.Workflows.WorkflowSubStatus;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Elsa.Workflows.IntegrationTests.Scenarios.WorkflowCancellation;
@ -77,7 +77,7 @@ public class ProtoActorTests
await _workflowServerHost.StartAsync(default);
const string workflowDefinitionId = nameof(SimpleSuspendedWorkflow);
var workflowState =
await _workflowRuntime.StartWorkflowAsync(workflowDefinitionId, new StartWorkflowRuntimeOptions());
await _workflowRuntime.StartWorkflowAsync(workflowDefinitionId, new StartWorkflowRuntimeParams());
Assert.Equal(WorkflowStatus.Running, workflowState.Status);
Assert.Equal(WorkflowSubStatus.Suspended, workflowState.SubStatus);
@ -91,8 +91,7 @@ public class ProtoActorTests
Assert.Empty(_capturingTextWriter.Lines);
}
[Fact(DisplayName = "Cancelling a running workflow",
Skip = "Unpredictable result, need to create a dispatcher for tests that will run outside of the unit test")]
[Fact(DisplayName = "Cancelling a running workflow", Skip = "Unpredictable result, need to create a dispatcher for tests that will run outside of the unit test")]
public async Task RunningCancelTest()
{
// Populate registries.
@ -103,10 +102,10 @@ public class ProtoActorTests
const string workflowDefinitionId = nameof(BulkSuspendedWorkflow);
var workflowState =
await _workflowRuntime.StartWorkflowAsync(workflowDefinitionId, new StartWorkflowRuntimeOptions());
await _workflowRuntime.StartWorkflowAsync(workflowDefinitionId, new StartWorkflowRuntimeParams());
var bookmarks = new Stack<Bookmark>(workflowState.Bookmarks);
var resumeOptions = new ResumeWorkflowRuntimeOptions
var resumeOptions = new ResumeWorkflowRuntimeParams
{
BookmarkId = bookmarks.Pop().Id
};

View file

@ -1,5 +1,4 @@
using Elsa.Scheduling.Activities;
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Runtime.Activities;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Models;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Runtime.Activities;

View file

@ -1,5 +1,4 @@
using Elsa.Extensions;
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;

View file

@ -1,7 +1,6 @@
using Elsa.Extensions;
using Elsa.Testing.Shared;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Activities.Flowchart.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Management.Contracts;
using Elsa.Workflows.Memory;

View file

@ -1,4 +1,3 @@
using Elsa.Workflows;
using Elsa.Workflows.Contracts;
namespace Elsa.Workflows.IntegrationTests.Serialization.VariableTypes;