Add workflow registry
This commit introduces a workflow registry for dynamically creating and registering workflows. It also includes a typed workflow materializer and extends existing services to support the new functionality. Changes are made across multiple files to integrate these new components and enhance the overall workflow functionalities.
This commit is contained in:
parent
0785fa6e42
commit
fa21cba51f
|
|
@ -6,6 +6,7 @@
|
|||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
using System.Net;
|
||||
using Elsa.Abstractions;
|
||||
using Elsa.Http;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.Models;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Options;
|
||||
|
||||
namespace Elsa.Server.Web.Endpoints.DynamicWorkflows.Post;
|
||||
|
||||
public class Post(IWorkflowRegistry workflowRegistry, IWorkflowRuntime workflowRuntime) : ElsaEndpointWithoutRequest
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/dynamic-workflows");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
var workflow = new Workflow
|
||||
{
|
||||
Identity = new WorkflowIdentity("DynamicWorkflow1", 1, "DynamicWorkflow1:v1"),
|
||||
Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new WriteLine("Step 1"),
|
||||
new WriteLine("Step 2"),
|
||||
new WriteLine("Step 3")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await workflowRegistry.RegisterAsync(workflow, ct);
|
||||
await workflowRuntime.StartWorkflowAsync("DynamicWorkflow1", new StartWorkflowRuntimeOptions());
|
||||
}
|
||||
}
|
||||
|
|
@ -228,6 +228,7 @@ services
|
|||
|
||||
elsa.InstallDropIns(options => options.DropInRootDirectory = Path.Combine(Directory.GetCurrentDirectory(), "App_Data", "DropIns"));
|
||||
elsa.AddSwagger();
|
||||
elsa.AddFastEndpointsAssembly<Program>();
|
||||
});
|
||||
|
||||
services.AddHealthChecks();
|
||||
|
|
|
|||
|
|
@ -167,6 +167,7 @@ public class WorkflowManagementFeature : FeatureBase
|
|||
.AddScoped<IExpressionDescriptorRegistry, ExpressionDescriptorRegistry>()
|
||||
.AddScoped<IExpressionDescriptorProvider, DefaultExpressionDescriptorProvider>()
|
||||
.AddScoped<ISerializationOptionsConfigurator, SerializationOptionsConfigurator>()
|
||||
.AddScoped<IWorkflowMaterializer, TypedWorkflowMaterializer>()
|
||||
.AddScoped<IWorkflowMaterializer, ClrWorkflowMaterializer>()
|
||||
.AddScoped<IWorkflowMaterializer, JsonWorkflowMaterializer>()
|
||||
.AddScoped<IActivityResolver, WorkflowDefinitionActivityResolver>()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.Contracts;
|
||||
using Elsa.Workflows.Management.Contracts;
|
||||
using Elsa.Workflows.Management.Entities;
|
||||
using Elsa.Workflows.Management.Mappers;
|
||||
using Elsa.Workflows.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.Management.Materializers;
|
||||
|
||||
/// <summary>
|
||||
/// A workflow materializer that deserializes workflows created in C# code.
|
||||
/// </summary>
|
||||
public class TypedWorkflowMaterializer(WorkflowDefinitionMapper workflowDefinitionMapper) : IWorkflowMaterializer
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the materializer.
|
||||
/// </summary>
|
||||
public const string MaterializerName = "Typed";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => MaterializerName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask<Workflow> MaterializeAsync(WorkflowDefinition definition, CancellationToken cancellationToken)
|
||||
{
|
||||
var workflow = ToWorkflow(definition);
|
||||
return new ValueTask<Workflow>(workflow);
|
||||
}
|
||||
|
||||
private Workflow ToWorkflow(WorkflowDefinition definition) => workflowDefinitionMapper.Map(definition);
|
||||
}
|
||||
|
|
@ -35,12 +35,12 @@ public class WorkflowDefinitionService : IWorkflowDefinitionService
|
|||
public async Task<Workflow> MaterializeWorkflowAsync(WorkflowDefinition definition, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var materializers = _materializers();
|
||||
var provider = materializers.FirstOrDefault(x => x.Name == definition.MaterializerName);
|
||||
var materializer = materializers.FirstOrDefault(x => x.Name == definition.MaterializerName);
|
||||
|
||||
if (provider == null)
|
||||
if (materializer == null)
|
||||
throw new Exception("Provider not found");
|
||||
|
||||
var workflow = await provider.MaterializeAsync(definition, cancellationToken);
|
||||
var workflow = await materializer.MaterializeAsync(definition, cancellationToken);
|
||||
var graph = (await _activityVisitor.VisitAsync(workflow, cancellationToken)).Flatten().ToList();
|
||||
|
||||
// Assign identities.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Elsa.Workflows.Management.Contracts;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
|
||||
namespace Elsa.Workflows.Runtime.Contracts;
|
||||
|
||||
|
|
@ -12,4 +13,11 @@ public interface IWorkflowDefinitionStorePopulator
|
|||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
Task PopulateStoreAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a workflow definition to the store.
|
||||
/// </summary>
|
||||
/// <param name="materializedWorkflow">A materialized workflow.</param>
|
||||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
Task AddAsync(MaterializedWorkflow materializedWorkflow, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using Elsa.Workflows.Activities;
|
||||
|
||||
namespace Elsa.Workflows.Runtime.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Registers workflows.
|
||||
/// </summary>
|
||||
public interface IWorkflowRegistry
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers a workflow.
|
||||
/// </summary>
|
||||
/// <param name="workflow">The workflow to register.</param>
|
||||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
Task RegisterAsync(Workflow workflow, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -165,6 +165,7 @@ public class WorkflowRuntimeFeature : FeatureBase
|
|||
.AddScoped<IActivityExecutionMapper, DefaultActivityExecutionMapper>()
|
||||
.AddScoped<IWorkflowDefinitionStorePopulator, DefaultWorkflowDefinitionStorePopulator>()
|
||||
.AddScoped<IRegistriesPopulator, DefaultRegistriesPopulator>()
|
||||
.AddScoped<IWorkflowRegistry, DefaultWorkflowRegistry>()
|
||||
.AddScoped<ITaskReporter, TaskReporter>()
|
||||
.AddScoped<SynchronousTaskDispatcher>()
|
||||
.AddScoped<BackgroundTaskDispatcher>()
|
||||
|
|
|
|||
|
|
@ -53,12 +53,18 @@ public class DefaultWorkflowDefinitionStorePopulator : IWorkflowDefinitionStoreP
|
|||
|
||||
foreach (var result in results)
|
||||
{
|
||||
await AssignIdentities(result.Workflow, cancellationToken);
|
||||
await AddOrUpdateAsync(result, cancellationToken);
|
||||
await IndexTriggersAsync(result, cancellationToken);
|
||||
await AddAsync(result, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task AddAsync(MaterializedWorkflow materializedWorkflow, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await AssignIdentities(materializedWorkflow.Workflow, cancellationToken);
|
||||
await AddOrUpdateAsync(materializedWorkflow, cancellationToken);
|
||||
await IndexTriggersAsync(materializedWorkflow, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task AssignIdentities(Workflow workflow, CancellationToken cancellationToken)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.Management.Materializers;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
|
||||
namespace Elsa.Workflows.Runtime.Services;
|
||||
|
||||
/// <inheritdoc />
|
||||
public class DefaultWorkflowRegistry(IWorkflowDefinitionStorePopulator populator) : IWorkflowRegistry
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task RegisterAsync(Workflow workflow, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var materializedWorkflow = new MaterializedWorkflow(workflow, nameof(DefaultWorkflowRegistry), TypedWorkflowMaterializer.MaterializerName);
|
||||
await populator.AddAsync(materializedWorkflow, cancellationToken);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue