Added Service for searching through ActivityRegistry
Added Refreshing of registry on miss when searching
This commit is contained in:
parent
2abe58fa10
commit
b092d62bcc
|
|
@ -22,12 +22,12 @@ public interface IFunctionActivityRegistry
|
|||
/// </summary>
|
||||
/// <param name="descriptor">The descriptor that describes the function.</param>
|
||||
void RegisterFunction(FunctionActivityDescriptor descriptor);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a function to an activity that can be invoked from a DSL script.
|
||||
/// </summary>
|
||||
/// <param name="functionName">The name of the function.</param>
|
||||
/// <param name="arguments">The arguments that are passed to the function.</param>
|
||||
/// <returns>An activity that can be invoked from a DSL script.</returns>
|
||||
IActivity ResolveFunction(string functionName, IEnumerable<object?>? arguments = default);
|
||||
Task<IActivity> ResolveFunction(string functionName, IEnumerable<object?>? arguments = default);
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ public partial class WorkflowDefinitionBuilderInterpreter
|
|||
var functionName = context.ID().GetText();
|
||||
var argsNode = context.args();
|
||||
var args = argsNode != null ? _argValues.Get(context.args()) : default;
|
||||
var activity = _functionActivityRegistry.ResolveFunction(functionName, args);
|
||||
var activity = _functionActivityRegistry.ResolveFunction(functionName, args).GetAwaiter().GetResult();
|
||||
|
||||
_expressionValue.Put(context, activity);
|
||||
return DefaultResult;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public partial class WorkflowDefinitionBuilderInterpreter
|
|||
/// <inheritdoc />
|
||||
public override IWorkflowBuilder VisitObject(ElsaParser.ObjectContext context)
|
||||
{
|
||||
var @object = GetObject(context);
|
||||
var @object = GetObject(context).GetAwaiter().GetResult();
|
||||
|
||||
_object.Put(context, @object);
|
||||
_expressionValue.Put(context, @object);
|
||||
|
|
@ -38,12 +38,12 @@ public partial class WorkflowDefinitionBuilderInterpreter
|
|||
return DefaultResult;
|
||||
}
|
||||
|
||||
private object GetObject(ElsaParser.ObjectContext context)
|
||||
private async Task<object> GetObject(ElsaParser.ObjectContext context)
|
||||
{
|
||||
var objectTypeName = context.ID().GetText();
|
||||
|
||||
// First, check if the symbol matches an activity type.
|
||||
var activityDescriptor = _activityRegistry.Find(x => x.Name == objectTypeName);
|
||||
var activityDescriptor = await _activityRegistryLookup.Find(x => x.Name == objectTypeName);
|
||||
|
||||
if (activityDescriptor != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace Elsa.Dsl.Interpreters;
|
|||
public partial class WorkflowDefinitionBuilderInterpreter : ElsaParserBaseVisitor<IWorkflowBuilder>
|
||||
{
|
||||
private readonly ITypeSystem _typeSystem;
|
||||
private readonly IActivityRegistry _activityRegistry;
|
||||
private readonly IActivityRegistryLookupService _activityRegistryLookup;
|
||||
private readonly IFunctionActivityRegistry _functionActivityRegistry;
|
||||
private readonly IWorkflowBuilder _workflowBuilder;
|
||||
private readonly ParseTreeProperty<object> _object = new();
|
||||
|
|
@ -22,12 +22,12 @@ public partial class WorkflowDefinitionBuilderInterpreter : ElsaParserBaseVisito
|
|||
/// <inheritdoc />
|
||||
public WorkflowDefinitionBuilderInterpreter(
|
||||
ITypeSystem typeSystem,
|
||||
IActivityRegistry activityRegistry,
|
||||
IActivityRegistryLookupService activityRegistryLookup,
|
||||
IFunctionActivityRegistry functionActivityRegistry,
|
||||
IWorkflowBuilderFactory workflowBuilderFactory)
|
||||
{
|
||||
_typeSystem = typeSystem;
|
||||
_activityRegistry = activityRegistry;
|
||||
_activityRegistryLookup = activityRegistryLookup;
|
||||
_functionActivityRegistry = functionActivityRegistry;
|
||||
_workflowBuilder = workflowBuilderFactory.CreateBuilder();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace Elsa.Dsl.Services;
|
|||
public class DslEngine : IDslEngine
|
||||
{
|
||||
private readonly ITypeSystem _typeSystem;
|
||||
private readonly IActivityRegistry _activityRegistry;
|
||||
private readonly IActivityRegistryLookupService _activityRegistryLookup;
|
||||
private readonly IFunctionActivityRegistry _functionActivityRegistry;
|
||||
private readonly IWorkflowBuilderFactory _workflowBuilderFactory;
|
||||
|
||||
|
|
@ -19,12 +19,12 @@ public class DslEngine : IDslEngine
|
|||
/// </summary>
|
||||
public DslEngine(
|
||||
ITypeSystem typeSystem,
|
||||
IActivityRegistry activityRegistry,
|
||||
IActivityRegistryLookupService activityRegistryLookup,
|
||||
IFunctionActivityRegistry functionActivityRegistry,
|
||||
IWorkflowBuilderFactory workflowBuilderFactory)
|
||||
{
|
||||
_typeSystem = typeSystem;
|
||||
_activityRegistry = activityRegistry;
|
||||
_activityRegistryLookup = activityRegistryLookup;
|
||||
_functionActivityRegistry = functionActivityRegistry;
|
||||
_workflowBuilderFactory = workflowBuilderFactory;
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ public class DslEngine : IDslEngine
|
|||
|
||||
var interpreter = new WorkflowDefinitionBuilderInterpreter(
|
||||
_typeSystem,
|
||||
_activityRegistry,
|
||||
_activityRegistryLookup,
|
||||
_functionActivityRegistry,
|
||||
_workflowBuilderFactory);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,15 +12,15 @@ namespace Elsa.Dsl.Services;
|
|||
/// <inheritdoc />
|
||||
public class FunctionActivityRegistry : IFunctionActivityRegistry
|
||||
{
|
||||
private readonly IActivityRegistry _activityRegistry;
|
||||
private readonly IActivityRegistryLookupService _activityRegistryLookup;
|
||||
private readonly IDictionary<string, FunctionActivityDescriptor> _dictionary = new Dictionary<string, FunctionActivityDescriptor>();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="FunctionActivityRegistry"/> class.
|
||||
/// </summary>
|
||||
public FunctionActivityRegistry(IActivityRegistry activityRegistry)
|
||||
public FunctionActivityRegistry(IActivityRegistryLookupService activityRegistryLookup)
|
||||
{
|
||||
_activityRegistry = activityRegistry;
|
||||
_activityRegistryLookup = activityRegistryLookup;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -37,12 +37,12 @@ public class FunctionActivityRegistry : IFunctionActivityRegistry
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IActivity ResolveFunction(string functionName, IEnumerable<object?>? arguments = default)
|
||||
public async Task<IActivity> ResolveFunction(string functionName, IEnumerable<object?>? arguments = default)
|
||||
{
|
||||
if (!_dictionary.TryGetValue(functionName, out var descriptor))
|
||||
throw new Exception($"Could not resolve function {functionName}. Did you forget to register it?");
|
||||
|
||||
var activityDescriptor = _activityRegistry.Find(x => x.Name == descriptor.ActivityTypeName || x.TypeName == descriptor.ActivityTypeName);
|
||||
var activityDescriptor = await _activityRegistryLookup.Find(x => x.Name == descriptor.ActivityTypeName || x.TypeName == descriptor.ActivityTypeName);
|
||||
|
||||
if (activityDescriptor == null)
|
||||
throw new Exception($"Could not find activity descriptor for activity type {descriptor.ActivityTypeName}");
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
CreateWorkflowInputAccessors(engine, context);
|
||||
|
||||
// Create output getters for each activity.
|
||||
CreateActivityOutputAccessors(engine, context);
|
||||
await CreateActivityOutputAccessors(engine, context);
|
||||
|
||||
// Create argument getters for each argument.
|
||||
foreach (var argument in options.Arguments)
|
||||
|
|
@ -171,11 +171,11 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
}
|
||||
}
|
||||
|
||||
private static void CreateActivityOutputAccessors(Engine engine, ExpressionExecutionContext context)
|
||||
private static async Task CreateActivityOutputAccessors(Engine engine, ExpressionExecutionContext context)
|
||||
{
|
||||
var activityOutputs = context.GetActivityOutputs();
|
||||
|
||||
foreach (var activityOutput in activityOutputs)
|
||||
await foreach (var activityOutput in activityOutputs)
|
||||
foreach (var outputName in activityOutput.OutputNames)
|
||||
engine.SetValue($"get{outputName}From{activityOutput.ActivityName}", (Func<object?>)(() => context.GetOutput(activityOutput.ActivityId, outputName)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@ namespace Elsa.JavaScript.TypeDefinitions.Providers;
|
|||
internal class ActivityOutputFunctionsDefinitionProvider : FunctionDefinitionProvider
|
||||
{
|
||||
private readonly IActivityVisitor _activityVisitor;
|
||||
private readonly IActivityRegistry _activityRegistry;
|
||||
private readonly IActivityRegistryLookupService _activityRegistryLookup;
|
||||
private readonly IIdentityGraphService _identityGraphService;
|
||||
|
||||
public ActivityOutputFunctionsDefinitionProvider(IActivityVisitor activityVisitor, IActivityRegistry activityRegistry, IIdentityGraphService identityGraphService)
|
||||
public ActivityOutputFunctionsDefinitionProvider(IActivityVisitor activityVisitor, IActivityRegistryLookupService activityRegistryLookup, IIdentityGraphService identityGraphService)
|
||||
{
|
||||
_activityVisitor = activityVisitor;
|
||||
_activityRegistry = activityRegistry;
|
||||
_activityRegistryLookup = activityRegistryLookup;
|
||||
_identityGraphService = identityGraphService;
|
||||
}
|
||||
|
||||
|
|
@ -29,12 +29,12 @@ internal class ActivityOutputFunctionsDefinitionProvider : FunctionDefinitionPro
|
|||
var nodes = (await _activityVisitor.VisitAsync(workflow.Root, context.CancellationToken)).Flatten().Distinct().ToList();
|
||||
|
||||
// Ensure identities.
|
||||
_identityGraphService.AssignIdentities(nodes);
|
||||
await _identityGraphService.AssignIdentities(nodes);
|
||||
|
||||
var activitiesWithOutputs = nodes.GetActivitiesWithOutputs(_activityRegistry);
|
||||
var activitiesWithOutputs = nodes.GetActivitiesWithOutputs(_activityRegistryLookup);
|
||||
var definitions = new List<FunctionDefinition>();
|
||||
|
||||
foreach (var (activity, activityDescriptor) in activitiesWithOutputs)
|
||||
await foreach (var (activity, activityDescriptor) in activitiesWithOutputs)
|
||||
{
|
||||
definitions.AddRange(from output in activityDescriptor.Outputs
|
||||
select output.Name.Pascalize()
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ namespace Elsa.Workflows.Api.Endpoints.ActivityDescriptorOptions.Get;
|
|||
internal class Get : ElsaEndpoint<Request, Response>
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IActivityRegistry _registry;
|
||||
private readonly IActivityRegistryLookupService _registryLookup;
|
||||
private readonly IPropertyUIHandlerResolver _optionsResolver;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Get(IServiceProvider serviceProvider, IActivityRegistry registry, IPropertyUIHandlerResolver optionsResolver)
|
||||
public Get(IServiceProvider serviceProvider, IActivityRegistryLookupService registryLookup, IPropertyUIHandlerResolver optionsResolver)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_registry = registry;
|
||||
_registryLookup = registryLookup;
|
||||
_optionsResolver = optionsResolver;
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ internal class Get : ElsaEndpoint<Request, Response>
|
|||
/// <inheritdoc />
|
||||
public override async Task HandleAsync(Request request, CancellationToken cancellationToken)
|
||||
{
|
||||
var descriptor = request.Version == null ? _registry.Find(request.ActivityTypeName) : _registry.Find(request.ActivityTypeName, request.Version.Value);
|
||||
var descriptor = request.Version == null ? await _registryLookup.Find(request.ActivityTypeName) : await _registryLookup.Find(request.ActivityTypeName, request.Version.Value);
|
||||
if (descriptor == null)
|
||||
await SendNotFoundAsync(cancellationToken);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ namespace Elsa.Workflows.Api.Endpoints.ActivityDescriptors.Get;
|
|||
[PublicAPI]
|
||||
internal class Get : ElsaEndpoint<Request, ActivityDescriptor>
|
||||
{
|
||||
private readonly IActivityRegistry _registry;
|
||||
private readonly IActivityRegistryLookupService _registryLookup;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Get(IActivityRegistry registry)
|
||||
public Get(IActivityRegistryLookupService registryLookup)
|
||||
{
|
||||
_registry = registry;
|
||||
_registryLookup = registryLookup;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -26,7 +26,7 @@ internal class Get : ElsaEndpoint<Request, ActivityDescriptor>
|
|||
/// <inheritdoc />
|
||||
public override async Task HandleAsync(Request request, CancellationToken cancellationToken)
|
||||
{
|
||||
var descriptor = request.Version == null ? _registry.Find(request.TypeName) : _registry.Find(request.TypeName, request.Version.Value);
|
||||
var descriptor = request.Version == null ? await _registryLookup.Find(request.TypeName) : await _registryLookup.Find(request.TypeName, request.Version.Value);
|
||||
|
||||
if (descriptor == null)
|
||||
await SendNotFoundAsync(cancellationToken);
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ public class WorkflowBuilder : IWorkflowBuilder
|
|||
await _activityRegistry.RegisterAsync(distinctActivityTypes, cancellationToken);
|
||||
|
||||
// Assign identities to all activities.
|
||||
_identityGraphService.AssignIdentities(nodes);
|
||||
await _identityGraphService.AssignIdentities(nodes);
|
||||
|
||||
// Give unnamed variables in each variable container a predictable name.
|
||||
var variableContainers = nodes.Where(x => x.Activity is IVariableContainer).Select(x => (IVariableContainer)x.Activity).ToList();
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ public partial class WorkflowExecutionContext : IExecutionContext
|
|||
ServiceProvider = serviceProvider;
|
||||
SystemClock = serviceProvider.GetRequiredService<ISystemClock>();
|
||||
ActivityRegistry = serviceProvider.GetRequiredService<IActivityRegistry>();
|
||||
ActivityRegistryLookup = serviceProvider.GetRequiredService<IActivityRegistryLookupService>();
|
||||
_hasher = serviceProvider.GetRequiredService<IHasher>();
|
||||
SubStatus = WorkflowSubStatus.Pending;
|
||||
Id = id;
|
||||
|
|
@ -152,7 +153,7 @@ public partial class WorkflowExecutionContext : IExecutionContext
|
|||
cancellationTokens);
|
||||
|
||||
var workflowStateExtractor = serviceProvider.GetRequiredService<IWorkflowStateExtractor>();
|
||||
workflowStateExtractor.Apply(workflowExecutionContext, workflowState);
|
||||
await workflowStateExtractor.Apply(workflowExecutionContext, workflowState);
|
||||
|
||||
return workflowExecutionContext;
|
||||
}
|
||||
|
|
@ -228,6 +229,11 @@ public partial class WorkflowExecutionContext : IExecutionContext
|
|||
/// </summary>
|
||||
public IActivityRegistry ActivityRegistry { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IActivityRegistryLookupService"/>.
|
||||
/// </summary>
|
||||
public IActivityRegistryLookupService ActivityRegistryLookup { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the workflow graph.
|
||||
/// </summary>
|
||||
|
|
@ -572,9 +578,9 @@ public partial class WorkflowExecutionContext : IExecutionContext
|
|||
/// <summary>
|
||||
/// Creates a new <see cref="ActivityExecutionContext"/> for the specified activity.
|
||||
/// </summary>
|
||||
public ActivityExecutionContext CreateActivityExecutionContext(IActivity activity, ActivityInvocationOptions? options = default)
|
||||
public async Task<ActivityExecutionContext> CreateActivityExecutionContext(IActivity activity, ActivityInvocationOptions? options = default)
|
||||
{
|
||||
var activityDescriptor = ActivityRegistry.Find(activity) ?? throw new Exception($"Activity with type {activity.Type} not found in registry");
|
||||
var activityDescriptor = await ActivityRegistryLookup.Find(activity) ?? throw new Exception($"Activity with type {activity.Type} not found in registry");
|
||||
var tag = options?.Tag;
|
||||
var parentContext = options?.Owner;
|
||||
var parentExpressionExecutionContext = parentContext?.ExpressionExecutionContext ?? ExpressionExecutionContext;
|
||||
|
|
|
|||
|
|
@ -14,13 +14,6 @@ public interface IActivityRegistry : IActivityProvider
|
|||
/// <param name="descriptor">The activity descriptor to add.</param>
|
||||
void Add(Type providerType, ActivityDescriptor descriptor);
|
||||
|
||||
/// <summary>
|
||||
/// Adds multiple activity descriptors to the registry.
|
||||
/// </summary>
|
||||
/// <param name="providerType">The type of the activity provider.</param>
|
||||
/// <param name="descriptors">The activity descriptors to add.</param>
|
||||
void AddMany(Type providerType, IEnumerable<ActivityDescriptor> descriptors);
|
||||
|
||||
/// <summary>
|
||||
/// Removes an activity descriptor from the registry.
|
||||
/// </summary>
|
||||
|
|
@ -28,17 +21,6 @@ public interface IActivityRegistry : IActivityProvider
|
|||
/// <param name="descriptor">The activity descriptor to remove.</param>
|
||||
void Remove(Type providerType, ActivityDescriptor descriptor);
|
||||
|
||||
/// <summary>
|
||||
/// Clears all activity descriptors from the registry.
|
||||
/// </summary>
|
||||
void Clear();
|
||||
|
||||
/// <summary>
|
||||
/// Clears all activity descriptors provided by the specified provider.
|
||||
/// </summary>
|
||||
/// <param name="providerType">The type of the activity provider.</param>
|
||||
void ClearProvider(Type providerType);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all activity descriptors in the registry.
|
||||
/// </summary>
|
||||
|
|
@ -100,4 +82,12 @@ public interface IActivityRegistry : IActivityProvider
|
|||
/// <param name="activityTypes">The activity types to register.</param>
|
||||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
Task RegisterAsync(IEnumerable<Type> activityTypes, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the activity descriptors in the registry by querying the specified activity providers.
|
||||
/// </summary>
|
||||
/// <param name="activityProviders">The activity providers used to retrieve the descriptors.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
Task RefreshDescriptors(IEnumerable<IActivityProvider> activityProviders, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
using Elsa.Workflows.Models;
|
||||
|
||||
namespace Elsa.Workflows.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a service for looking up activity descriptors.
|
||||
/// </summary>
|
||||
public interface IActivityRegistryLookupService
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the activity descriptor for the specified activity type.
|
||||
/// </summary>
|
||||
/// <param name="type">The activity type.</param>
|
||||
/// <returns>The activity descriptor for the specified activity type.</returns>
|
||||
Task<ActivityDescriptor?> Find(string type);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the activity descriptor for the specified activity type and version.
|
||||
/// </summary>
|
||||
/// <param name="type">The activity type.</param>
|
||||
/// <param name="version">The activity version.</param>
|
||||
/// <returns>The activity descriptor for the specified activity type and version.</returns>
|
||||
Task<ActivityDescriptor?> Find(string type, int version);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the activity descriptor matching the specified predicate.
|
||||
/// </summary>
|
||||
/// <param name="predicate">The predicate to match.</param>
|
||||
/// <returns>The activity descriptor matching the specified predicate.</returns>
|
||||
Task<ActivityDescriptor?> Find(Func<ActivityDescriptor, bool> predicate);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all activity descriptors matching the specified predicate.
|
||||
/// </summary>
|
||||
/// <param name="predicate">The predicate to match.</param>
|
||||
/// <returns>All activity descriptors matching the specified predicate.</returns>
|
||||
IEnumerable<ActivityDescriptor> FindMany(Func<ActivityDescriptor, bool> predicate);
|
||||
}
|
||||
|
|
@ -21,17 +21,17 @@ public interface IIdentityGraphService
|
|||
/// <summary>
|
||||
/// Assign unique identities tot the specified <see cref="ActivityNode"/> graph.
|
||||
/// </summary>
|
||||
void AssignIdentities(ActivityNode root);
|
||||
Task AssignIdentities(ActivityNode root);
|
||||
|
||||
/// <summary>
|
||||
/// Assign unique identities tot the specified flattened list of <see cref="ActivityNode"/>s.
|
||||
/// </summary>
|
||||
void AssignIdentities(ICollection<ActivityNode> flattenedList);
|
||||
Task AssignIdentities(ICollection<ActivityNode> flattenedList);
|
||||
|
||||
/// <summary>
|
||||
/// Assign unique identities to input and output properties of the specified <see cref="IActivity"/> graph.
|
||||
/// </summary>
|
||||
void AssignInputOutputs(IActivity activity);
|
||||
Task AssignInputOutputs(IActivity activity);
|
||||
|
||||
/// <summary>
|
||||
/// Assign unique identities to variables of the specified <see cref="IVariableContainer"/>.
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ public interface IWorkflowStateExtractor
|
|||
/// <param name="workflowExecutionContext">The workflow execution context to map.</param>
|
||||
/// <returns>The mapped workflow state.</returns>
|
||||
WorkflowState Extract(WorkflowExecutionContext workflowExecutionContext);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Applies workflow state to a workflow execution context.
|
||||
/// </summary>
|
||||
/// <param name="workflowExecutionContext">The workflow execution context to map onto.</param>
|
||||
/// <param name="state">The workflow state to apply.</param>
|
||||
/// <returns>The updated workflow execution context.</returns>
|
||||
WorkflowExecutionContext Apply(WorkflowExecutionContext workflowExecutionContext, WorkflowState state);
|
||||
Task<WorkflowExecutionContext> Apply(WorkflowExecutionContext workflowExecutionContext, WorkflowState state);
|
||||
}
|
||||
|
|
@ -138,24 +138,24 @@ public static class ActivityExecutionContextExtensions
|
|||
/// <summary>
|
||||
/// Evaluates a specific input property of the activity.
|
||||
/// </summary>
|
||||
public static Task<object?> EvaluateInputPropertyAsync(this ActivityExecutionContext context, string inputName)
|
||||
public static async Task<object?> EvaluateInputPropertyAsync(this ActivityExecutionContext context, string inputName)
|
||||
{
|
||||
var activity = context.Activity;
|
||||
var activityRegistry = context.GetRequiredService<IActivityRegistry>();
|
||||
var activityDescriptor = activityRegistry.Find(activity.Type) ?? throw new Exception("Activity descriptor not found");
|
||||
var activityRegistryLookup = context.GetRequiredService<IActivityRegistryLookupService>();
|
||||
var activityDescriptor = await activityRegistryLookup.Find(activity.Type) ?? throw new Exception("Activity descriptor not found");
|
||||
var inputDescriptor = activityDescriptor.GetWrappedInputPropertyDescriptor(activity, inputName);
|
||||
|
||||
if (inputDescriptor == null)
|
||||
throw new Exception($"No input with name {inputName} could be found");
|
||||
|
||||
return EvaluateInputPropertyAsync(context, activityDescriptor, inputDescriptor);
|
||||
return await EvaluateInputPropertyAsync(context, activityDescriptor, inputDescriptor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a set of tuples containing the activity and its descriptor for all activities with outputs.
|
||||
/// </summary>
|
||||
/// <param name="activityExecutionContext">The <see cref="ActivityExecutionContext"/> being extended.</param>
|
||||
public static IEnumerable<(IActivity Activity, ActivityDescriptor ActivityDescriptor)> GetActivitiesWithOutputs(this ActivityExecutionContext activityExecutionContext)
|
||||
public static async IAsyncEnumerable<(IActivity Activity, ActivityDescriptor ActivityDescriptor)> GetActivitiesWithOutputs(this ActivityExecutionContext activityExecutionContext)
|
||||
{
|
||||
// Get current container.
|
||||
var currentContainerNode = activityExecutionContext.FindParentWithVariableContainer()?.ActivityNode;
|
||||
|
|
@ -168,28 +168,25 @@ public static class ActivityExecutionContextExtensions
|
|||
var containedNodes = workflowExecutionContext.Nodes.Where(x => x.Parents.Contains(currentContainerNode)).Distinct().ToList();
|
||||
|
||||
// Select activities with outputs.
|
||||
var activityRegistry = workflowExecutionContext.GetRequiredService<IActivityRegistry>();
|
||||
var activityRegistry = workflowExecutionContext.GetRequiredService<IActivityRegistryLookupService>();
|
||||
var activitiesWithOutputs = containedNodes.GetActivitiesWithOutputs(activityRegistry);
|
||||
|
||||
foreach (var (activity, activityDescriptor) in activitiesWithOutputs)
|
||||
await foreach (var (activity, activityDescriptor) in activitiesWithOutputs)
|
||||
yield return (activity, activityDescriptor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a set of tuples containing the activity and its descriptor for all activities with outputs.
|
||||
/// </summary>
|
||||
public static IEnumerable<(IActivity Activity, ActivityDescriptor ActivityDescriptor)> GetActivitiesWithOutputs(this IEnumerable<ActivityNode> nodes, IActivityRegistry activityRegistry)
|
||||
public static async IAsyncEnumerable<(IActivity activity, ActivityDescriptor activityDescriptor)> GetActivitiesWithOutputs(this IEnumerable<ActivityNode> nodes, IActivityRegistryLookupService activityRegistryLookup)
|
||||
{
|
||||
// Select activities with outputs.
|
||||
var activitiesWithOutputs =
|
||||
from node in nodes
|
||||
let activity = node.Activity
|
||||
let activityDescriptor = activityRegistry.Find(activity.Type, activity.Version)
|
||||
where activityDescriptor.Outputs.Any()
|
||||
select (activity, activityDescriptor);
|
||||
|
||||
foreach (var (activity, activityDescriptor) in activitiesWithOutputs)
|
||||
yield return (activity, activityDescriptor);
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
var activity = node.Activity;
|
||||
var activityDescriptor = await activityRegistryLookup.Find(activity.Type, activity.Version);
|
||||
if (activityDescriptor != null && activityDescriptor.Outputs.Any())
|
||||
yield return (activity, activityDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public static class ActivityRegistryExtensions
|
|||
/// <summary>
|
||||
/// Finds the activity descriptor for the specified activity.
|
||||
/// </summary>
|
||||
public static ActivityDescriptor? Find(this IActivityRegistry activityRegistry, IActivity activity) => activityRegistry.Find(activity.Type, activity.Version);
|
||||
public static Task<ActivityDescriptor?> Find(this IActivityRegistryLookupService activityRegistry, IActivity activity) => activityRegistry.Find(activity.Type, activity.Version);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the activity descriptor for the specified activity type.
|
||||
|
|
|
|||
|
|
@ -434,7 +434,7 @@ public static class ExpressionExecutionContextExtensions
|
|||
/// <summary>
|
||||
/// Returns all activity outputs.
|
||||
/// </summary>
|
||||
public static IEnumerable<ActivityOutputs> GetActivityOutputs(this ExpressionExecutionContext context)
|
||||
public static async IAsyncEnumerable<ActivityOutputs> GetActivityOutputs(this ExpressionExecutionContext context)
|
||||
{
|
||||
if (!context.TryGetActivityExecutionContext(out var activityExecutionContext))
|
||||
yield break;
|
||||
|
|
@ -445,7 +445,7 @@ public static class ExpressionExecutionContextExtensions
|
|||
if (useActivityName)
|
||||
activitiesWithOutputs = activitiesWithOutputs.Where(x => !string.IsNullOrWhiteSpace(x.Activity.Name));
|
||||
|
||||
foreach (var activityWithOutput in activitiesWithOutputs)
|
||||
await foreach (var activityWithOutput in activitiesWithOutputs)
|
||||
{
|
||||
var activity = activityWithOutput.Activity;
|
||||
var activityDescriptor = activityWithOutput.ActivityDescriptor;
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ public class WorkflowsFeature : FeatureBase
|
|||
.AddScoped<IBookmarkPayloadSerializer>(sp => ActivatorUtilities.CreateInstance<BookmarkPayloadSerializer>(sp))
|
||||
.AddSingleton<IActivityDescriber, ActivityDescriber>()
|
||||
.AddSingleton<IActivityRegistry, ActivityRegistry>()
|
||||
.AddScoped<IActivityRegistryLookupService, ActivityRegistryLookupService>()
|
||||
.AddSingleton<IPropertyDefaultValueResolver, PropertyDefaultValueResolver>()
|
||||
.AddSingleton<IPropertyUIHandlerResolver, PropertyUIHandlerResolver>()
|
||||
.AddSingleton<IActivityFactory, ActivityFactory>()
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public class ActivityInvoker : IActivityInvoker
|
|||
if (activityExecutionContext == null)
|
||||
{
|
||||
// Create a new activity execution context.
|
||||
activityExecutionContext = workflowExecutionContext.CreateActivityExecutionContext(activity, options);
|
||||
activityExecutionContext = await workflowExecutionContext.CreateActivityExecutionContext(activity, options);
|
||||
|
||||
// Add the activity context to the workflow context.
|
||||
workflowExecutionContext.AddActivityExecutionContext(activityExecutionContext);
|
||||
|
|
|
|||
|
|
@ -7,37 +7,15 @@ using Microsoft.Extensions.Logging;
|
|||
namespace Elsa.Workflows.Services;
|
||||
|
||||
/// <inheritdoc />
|
||||
public class ActivityRegistry : IActivityRegistry
|
||||
public class ActivityRegistry(IActivityDescriber activityDescriber, IEnumerable<IActivityDescriptorModifier> modifiers, ILogger<ActivityRegistry> logger) : IActivityRegistry
|
||||
{
|
||||
private readonly IActivityDescriber _activityDescriber;
|
||||
private readonly IEnumerable<IActivityDescriptorModifier> _modifiers;
|
||||
private readonly ILogger _logger;
|
||||
private readonly ISet<ActivityDescriptor> _manualActivityDescriptors = new HashSet<ActivityDescriptor>();
|
||||
private readonly ConcurrentDictionary<Type, ICollection<ActivityDescriptor>> _providedActivityDescriptors = new();
|
||||
private readonly ConcurrentDictionary<(string Type, int Version), ActivityDescriptor> _activityDescriptors = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ActivityRegistry"/> class.
|
||||
/// </summary>
|
||||
public ActivityRegistry(IActivityDescriber activityDescriber, IEnumerable<IActivityDescriptorModifier> modifiers, ILogger<ActivityRegistry> logger)
|
||||
{
|
||||
_activityDescriber = activityDescriber;
|
||||
_modifiers = modifiers;
|
||||
_logger = logger;
|
||||
}
|
||||
private ConcurrentDictionary<Type, ICollection<ActivityDescriptor>> _providedActivityDescriptors = new();
|
||||
private ConcurrentDictionary<(string Type, int Version), ActivityDescriptor> _activityDescriptors = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(Type providerType, ActivityDescriptor descriptor) => Add(descriptor, GetOrCreateDescriptors(providerType));
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AddMany(Type providerType, IEnumerable<ActivityDescriptor> descriptors)
|
||||
{
|
||||
var target = GetOrCreateDescriptors(providerType);
|
||||
|
||||
foreach (var descriptor in descriptors)
|
||||
Add(descriptor, target);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Remove(Type providerType, ActivityDescriptor descriptor)
|
||||
{
|
||||
|
|
@ -45,24 +23,6 @@ public class ActivityRegistry : IActivityRegistry
|
|||
_activityDescriptors.Remove((descriptor.TypeName, descriptor.Version), out _);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Clear()
|
||||
{
|
||||
_activityDescriptors.Clear();
|
||||
_providedActivityDescriptors.Clear();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ClearProvider(Type providerType)
|
||||
{
|
||||
var descriptors = ListByProvider(providerType).ToList();
|
||||
|
||||
foreach (var descriptor in descriptors)
|
||||
_activityDescriptors.Remove((descriptor.TypeName, descriptor.Version), out _);
|
||||
|
||||
_providedActivityDescriptors.Remove(providerType, out _);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ActivityDescriptor> ListAll() => _activityDescriptors.Values;
|
||||
|
||||
|
|
@ -95,7 +55,7 @@ public class ActivityRegistry : IActivityRegistry
|
|||
if (_activityDescriptors.Values.Any(x => x.TypeName == activityTypeName))
|
||||
return;
|
||||
|
||||
var activityDescriptor = await _activityDescriber.DescribeActivityAsync(activityType, cancellationToken);
|
||||
var activityDescriptor = await activityDescriber.DescribeActivityAsync(activityType, cancellationToken);
|
||||
Add(GetType(), activityDescriptor);
|
||||
_manualActivityDescriptors.Add(activityDescriptor);
|
||||
}
|
||||
|
|
@ -106,24 +66,51 @@ public class ActivityRegistry : IActivityRegistry
|
|||
foreach (var activityType in activityTypes)
|
||||
await RegisterAsync(activityType, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask<IEnumerable<ActivityDescriptor>> GetDescriptorsAsync(CancellationToken cancellationToken = default) => new(_manualActivityDescriptors);
|
||||
|
||||
public async Task RefreshDescriptors(IEnumerable<IActivityProvider> activityProviders, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var providersDictionary = new ConcurrentDictionary<Type, ICollection<ActivityDescriptor>>();
|
||||
var activityDescriptors = new ConcurrentDictionary<(string Type, int Version), ActivityDescriptor>();
|
||||
foreach (IActivityProvider activityProvider in activityProviders)
|
||||
{
|
||||
var descriptors = (await activityProvider.GetDescriptorsAsync(cancellationToken)).ToList();
|
||||
var providerDescriptors = new List<ActivityDescriptor>();
|
||||
providersDictionary[activityProvider.GetType()] = providerDescriptors;
|
||||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
Add(descriptor, activityDescriptors, providerDescriptors);
|
||||
}
|
||||
}
|
||||
|
||||
Interlocked.Exchange(ref _activityDescriptors, activityDescriptors);
|
||||
Interlocked.Exchange(ref _providedActivityDescriptors, providersDictionary);
|
||||
}
|
||||
|
||||
private void Add(ActivityDescriptor descriptor, ICollection<ActivityDescriptor> target)
|
||||
{
|
||||
foreach (var modifier in _modifiers)
|
||||
Add(descriptor, _activityDescriptors, target);
|
||||
}
|
||||
|
||||
private void Add(ActivityDescriptor descriptor, ConcurrentDictionary<(string Type, int Version), ActivityDescriptor> activityDescriptors, ICollection<ActivityDescriptor> providerDescriptors)
|
||||
{
|
||||
foreach (var modifier in modifiers)
|
||||
modifier.Modify(descriptor);
|
||||
|
||||
// If the descriptor already exists, replace it. But log a warning.
|
||||
if (_activityDescriptors.TryGetValue((descriptor.TypeName, descriptor.Version), out var existingDescriptor))
|
||||
if (activityDescriptors.TryGetValue((descriptor.TypeName, descriptor.Version), out var existingDescriptor))
|
||||
{
|
||||
// Remove the existing descriptor from the target collection.
|
||||
target.Remove(existingDescriptor);
|
||||
// Remove the existing descriptor from the providerDescriptors collection.
|
||||
providerDescriptors.Remove(existingDescriptor);
|
||||
|
||||
// Log a warning.
|
||||
_logger.LogWarning("Activity descriptor {ActivityType} v{ActivityVersion} was already registered. Replacing with new descriptor", descriptor.TypeName, descriptor.Version);
|
||||
logger.LogWarning("Activity descriptor {ActivityType} v{ActivityVersion} was already registered. Replacing with new descriptor", descriptor.TypeName, descriptor.Version);
|
||||
}
|
||||
|
||||
_activityDescriptors[(descriptor.TypeName, descriptor.Version)] = descriptor;
|
||||
target.Add(descriptor);
|
||||
activityDescriptors[(descriptor.TypeName, descriptor.Version)] = descriptor;
|
||||
providerDescriptors.Add(descriptor);
|
||||
}
|
||||
|
||||
private ICollection<ActivityDescriptor> GetOrCreateDescriptors(Type provider)
|
||||
|
|
@ -136,7 +123,4 @@ public class ActivityRegistry : IActivityRegistry
|
|||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask<IEnumerable<ActivityDescriptor>> GetDescriptorsAsync(CancellationToken cancellationToken = default) => new(_manualActivityDescriptors);
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
using Elsa.Workflows.Contracts;
|
||||
using Elsa.Workflows.Models;
|
||||
|
||||
namespace Elsa.Workflows.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a service used to lookup activity descriptors in the activity registry.
|
||||
/// </summary>
|
||||
public class ActivityRegistryLookupService(IActivityRegistry activityRegistry, IEnumerable<IActivityProvider> providers) : IActivityRegistryLookupService
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<ActivityDescriptor?> Find(string type)
|
||||
{
|
||||
return Find(() => activityRegistry.Find(type));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ActivityDescriptor?> Find(string type, int version)
|
||||
{
|
||||
return Find(() => activityRegistry.Find(type, version));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ActivityDescriptor?> Find(Func<ActivityDescriptor, bool> predicate)
|
||||
{
|
||||
return Find(() => activityRegistry.Find(predicate));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ActivityDescriptor> FindMany(Func<ActivityDescriptor, bool> predicate)
|
||||
{
|
||||
return activityRegistry.FindMany(predicate);
|
||||
}
|
||||
|
||||
private async Task<ActivityDescriptor?> Find(Func<ActivityDescriptor?> findPredicate)
|
||||
{
|
||||
var descriptor = findPredicate.Invoke();
|
||||
if (descriptor is not null)
|
||||
return descriptor;
|
||||
|
||||
await activityRegistry.RefreshDescriptors(providers);
|
||||
return findPredicate.Invoke();
|
||||
}
|
||||
}
|
||||
|
|
@ -10,15 +10,15 @@ namespace Elsa.Workflows.Services;
|
|||
public class IdentityGraphService : IIdentityGraphService
|
||||
{
|
||||
private readonly IActivityVisitor _activityVisitor;
|
||||
private readonly IActivityRegistry _activityRegistry;
|
||||
private readonly IActivityRegistryLookupService _activityRegistryLookup;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public IdentityGraphService(IActivityVisitor activityVisitor, IActivityRegistry activityRegistry)
|
||||
public IdentityGraphService(IActivityVisitor activityVisitor, IActivityRegistryLookupService activityRegistryLookup)
|
||||
{
|
||||
_activityVisitor = activityVisitor;
|
||||
_activityRegistry = activityRegistry;
|
||||
_activityRegistryLookup = activityRegistryLookup;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -31,14 +31,14 @@ public class IdentityGraphService : IIdentityGraphService
|
|||
public async Task AssignIdentitiesAsync(IActivity root, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var graph = await _activityVisitor.VisitAsync(root, cancellationToken);
|
||||
AssignIdentities(graph);
|
||||
await AssignIdentities(graph);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AssignIdentities(ActivityNode root) => AssignIdentities(root.Flatten().ToList());
|
||||
public Task AssignIdentities(ActivityNode root) => AssignIdentities(root.Flatten().ToList());
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AssignIdentities(ICollection<ActivityNode> flattenedList)
|
||||
public async Task AssignIdentities(ICollection<ActivityNode> flattenedList)
|
||||
{
|
||||
var identityCounters = new Dictionary<string, int>();
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ public class IdentityGraphService : IIdentityGraphService
|
|||
{
|
||||
node.Activity.Id = CreateId(node, identityCounters, flattenedList);
|
||||
node.Activity.NodeId = node.NodeId;
|
||||
AssignInputOutputs(node.Activity);
|
||||
await AssignInputOutputs(node.Activity);
|
||||
|
||||
if (node.Activity is IVariableContainer variableContainer)
|
||||
AssignVariables(variableContainer);
|
||||
|
|
@ -54,9 +54,9 @@ public class IdentityGraphService : IIdentityGraphService
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AssignInputOutputs(IActivity activity)
|
||||
public async Task AssignInputOutputs(IActivity activity)
|
||||
{
|
||||
var activityDescriptor = _activityRegistry.Find(activity.Type, activity.Version) ?? throw new Exception("Activity descriptor not found");
|
||||
var activityDescriptor = await _activityRegistryLookup.Find(activity.Type, activity.Version) ?? throw new Exception("Activity descriptor not found");
|
||||
var inputDictionary = activityDescriptor.GetWrappedInputProperties(activity);
|
||||
|
||||
foreach (var (inputName, input) in inputDictionary)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ public class WorkflowGraphBuilder(IActivityVisitor activityVisitor, IIdentityGra
|
|||
var graph = await activityVisitor.VisitAsync(workflow, cancellationToken);
|
||||
var nodes = graph.Flatten().ToList();
|
||||
|
||||
identityGraphService.AssignIdentities(nodes);
|
||||
await identityGraphService.AssignIdentities(nodes);
|
||||
return new WorkflowGraph(workflow, graph, nodes);
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ public class WorkflowStateExtractor : IWorkflowStateExtractor
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public WorkflowExecutionContext Apply(WorkflowExecutionContext workflowExecutionContext, WorkflowState state)
|
||||
public async Task<WorkflowExecutionContext> Apply(WorkflowExecutionContext workflowExecutionContext, WorkflowState state)
|
||||
{
|
||||
workflowExecutionContext.Id = state.Id;
|
||||
workflowExecutionContext.CorrelationId = state.CorrelationId;
|
||||
|
|
@ -55,7 +55,7 @@ public class WorkflowStateExtractor : IWorkflowStateExtractor
|
|||
workflowExecutionContext.FinishedAt = state.FinishedAt;
|
||||
ApplyInput(state, workflowExecutionContext);
|
||||
ApplyProperties(state, workflowExecutionContext);
|
||||
ApplyActivityExecutionContexts(state, workflowExecutionContext);
|
||||
await ApplyActivityExecutionContexts(state, workflowExecutionContext);
|
||||
ApplyCompletionCallbacks(state, workflowExecutionContext);
|
||||
ApplyScheduledActivities(state, workflowExecutionContext);
|
||||
return workflowExecutionContext;
|
||||
|
|
@ -96,10 +96,10 @@ public class WorkflowStateExtractor : IWorkflowStateExtractor
|
|||
workflowExecutionContext.Properties[property.Key] = property.Value;
|
||||
}
|
||||
|
||||
private static void ApplyActivityExecutionContexts(WorkflowState state, WorkflowExecutionContext workflowExecutionContext)
|
||||
private static async Task ApplyActivityExecutionContexts(WorkflowState state, WorkflowExecutionContext workflowExecutionContext)
|
||||
{
|
||||
var activityExecutionContexts = state.ActivityExecutionContexts
|
||||
.Select(CreateActivityExecutionContext)
|
||||
var activityExecutionContexts = (await Task.WhenAll(
|
||||
state.ActivityExecutionContexts.Select(async item => await CreateActivityExecutionContext(item))))
|
||||
.Where(x => x != null)
|
||||
.Select(x => x!)
|
||||
.ToList();
|
||||
|
|
@ -128,7 +128,7 @@ public class WorkflowStateExtractor : IWorkflowStateExtractor
|
|||
workflowExecutionContext.ActivityExecutionContexts = activityExecutionContexts;
|
||||
return;
|
||||
|
||||
ActivityExecutionContext? CreateActivityExecutionContext(ActivityExecutionContextState activityExecutionContextState)
|
||||
async Task<ActivityExecutionContext?> CreateActivityExecutionContext(ActivityExecutionContextState activityExecutionContextState)
|
||||
{
|
||||
var activity = workflowExecutionContext.FindActivityByNodeId(activityExecutionContextState.ScheduledActivityNodeId);
|
||||
|
||||
|
|
@ -137,7 +137,7 @@ public class WorkflowStateExtractor : IWorkflowStateExtractor
|
|||
return null;
|
||||
|
||||
var properties = activityExecutionContextState.Properties;
|
||||
var activityExecutionContext = workflowExecutionContext.CreateActivityExecutionContext(activity);
|
||||
var activityExecutionContext = await workflowExecutionContext.CreateActivityExecutionContext(activity);
|
||||
activityExecutionContext.Id = activityExecutionContextState.Id;
|
||||
activityExecutionContext.Properties = properties;
|
||||
activityExecutionContext.ActivityState = activityExecutionContextState.ActivityState ?? new Dictionary<string, object>();
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public class WorkflowDefinitionActivity : Composite, IInitializable
|
|||
/// <inheritdoc />
|
||||
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
|
||||
{
|
||||
CopyInputOutputToVariables(context);
|
||||
await CopyInputOutputToVariables(context);
|
||||
await context.ScheduleActivityAsync(Root, OnChildCompletedAsync);
|
||||
}
|
||||
|
||||
|
|
@ -84,10 +84,10 @@ public class WorkflowDefinitionActivity : Composite, IInitializable
|
|||
await activityExecutionContext.CompleteActivityAsync(completeCompositeSignal?.Value);
|
||||
}
|
||||
|
||||
private void CopyInputOutputToVariables(ActivityExecutionContext context)
|
||||
private async Task CopyInputOutputToVariables(ActivityExecutionContext context)
|
||||
{
|
||||
var serviceProvider = context.GetRequiredService<IServiceProvider>();
|
||||
var activityDescriptor = FindActivityDescriptor(serviceProvider);
|
||||
var activityDescriptor = await FindActivityDescriptor(serviceProvider);
|
||||
|
||||
DeclareInputAsVariables(activityDescriptor, (descriptor, variable) =>
|
||||
{
|
||||
|
|
@ -99,7 +99,7 @@ public class WorkflowDefinitionActivity : Composite, IInitializable
|
|||
variable.Set(context, evaluatedExpression);
|
||||
});
|
||||
|
||||
DeclareOutputAsVariables(activityDescriptor, (descriptor, variable) => context.ExpressionExecutionContext.Memory.Declare(variable));
|
||||
DeclareOutputAsVariables(activityDescriptor, (_, variable) => context.ExpressionExecutionContext.Memory.Declare(variable));
|
||||
}
|
||||
|
||||
private void DeclareInputAsVariables(ActivityDescriptor activityDescriptor, Action<InputDescriptor, Variable> configureVariable)
|
||||
|
|
@ -165,10 +165,10 @@ public class WorkflowDefinitionActivity : Composite, IInitializable
|
|||
return workflowGraph;
|
||||
}
|
||||
|
||||
private ActivityDescriptor? FindActivityDescriptor(IServiceProvider serviceProvider)
|
||||
private async Task<ActivityDescriptor?> FindActivityDescriptor(IServiceProvider serviceProvider)
|
||||
{
|
||||
var activityRegistry = serviceProvider.GetRequiredService<IActivityRegistry>();
|
||||
return activityRegistry.Find(Type, Version) ?? activityRegistry.Find(Type);
|
||||
var activityRegistryLookup = serviceProvider.GetRequiredService<IActivityRegistryLookupService>();
|
||||
return await activityRegistryLookup.Find(Type, Version) ?? await activityRegistryLookup.Find(Type);
|
||||
}
|
||||
|
||||
async ValueTask IInitializable.InitializeAsync(InitializationContext context)
|
||||
|
|
@ -186,7 +186,7 @@ public class WorkflowDefinitionActivity : Composite, IInitializable
|
|||
if (workflowGraph == null)
|
||||
throw new Exception($"Could not find workflow definition with ID {WorkflowDefinitionId}.");
|
||||
|
||||
var activityDescriptor = FindActivityDescriptor(serviceProvider);
|
||||
var activityDescriptor = await FindActivityDescriptor(serviceProvider);
|
||||
|
||||
if (activityDescriptor == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,41 +7,18 @@ namespace Elsa.Workflows.Management.Services;
|
|||
/// <summary>
|
||||
/// Populates the <see cref="IActivityRegistry"/> with descriptors provided by <see cref="IActivityProvider"/>s.
|
||||
/// </summary>
|
||||
public class ActivityRegistryPopulator : IActivityRegistryPopulator
|
||||
public class ActivityRegistryPopulator(IEnumerable<IActivityProvider> providers, IActivityRegistry registry) : IActivityRegistryPopulator
|
||||
{
|
||||
private readonly IEnumerable<IActivityProvider> _providers;
|
||||
private readonly IActivityRegistry _registry;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public ActivityRegistryPopulator(IEnumerable<IActivityProvider> providers, IActivityRegistry registry)
|
||||
{
|
||||
_providers = providers;
|
||||
_registry = registry;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task PopulateRegistryAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_registry.Clear();
|
||||
|
||||
foreach (var provider in _providers)
|
||||
await PopulateRegistryAsync(provider, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task PopulateRegistryAsync(Type providerType, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_registry.ClearProvider(providerType);
|
||||
var provider = _providers.First(x => x.GetType() == providerType);
|
||||
await PopulateRegistryAsync(provider, cancellationToken);
|
||||
await registry.RefreshDescriptors(providers, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task AddToRegistry(Type providerType, string workflowDefinitionVersionId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var provider = _providers.First(x => x.GetType() == providerType);
|
||||
var provider = providers.First(x => x.GetType() == providerType);
|
||||
var descriptors = await provider.GetDescriptorsAsync(cancellationToken);
|
||||
var descriptorToAdd = descriptors
|
||||
.SingleOrDefault(d =>
|
||||
|
|
@ -49,13 +26,13 @@ public class ActivityRegistryPopulator : IActivityRegistryPopulator
|
|||
val.ToString() == workflowDefinitionVersionId);
|
||||
|
||||
if (descriptorToAdd is not null)
|
||||
_registry.Add(providerType, descriptorToAdd);
|
||||
registry.Add(providerType, descriptorToAdd);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RemoveDefinitionFromRegistry(Type providerType, string workflowDefinitionId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var providerDescriptors = _registry.ListByProvider(providerType);
|
||||
var providerDescriptors = registry.ListByProvider(providerType);
|
||||
|
||||
var descriptorsToRemove = providerDescriptors
|
||||
.Where(d =>
|
||||
|
|
@ -64,14 +41,14 @@ public class ActivityRegistryPopulator : IActivityRegistryPopulator
|
|||
|
||||
foreach (ActivityDescriptor activityDescriptor in descriptorsToRemove)
|
||||
{
|
||||
_registry.Remove(providerType, activityDescriptor);
|
||||
registry.Remove(providerType, activityDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RemoveDefinitionVersionFromRegistry(Type providerType, string workflowDefinitionVersionId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var providerDescriptors = _registry.ListByProvider(providerType);
|
||||
var providerDescriptors = registry.ListByProvider(providerType);
|
||||
|
||||
var descriptorToRemove = providerDescriptors
|
||||
.SingleOrDefault(d =>
|
||||
|
|
@ -79,12 +56,6 @@ public class ActivityRegistryPopulator : IActivityRegistryPopulator
|
|||
val.ToString() == workflowDefinitionVersionId);
|
||||
|
||||
if (descriptorToRemove is not null)
|
||||
_registry.Remove(providerType, descriptorToRemove);
|
||||
}
|
||||
|
||||
private async Task PopulateRegistryAsync(IActivityProvider provider, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var descriptors = await provider.GetDescriptorsAsync(cancellationToken);
|
||||
_registry.AddMany(provider.GetType(), descriptors);
|
||||
registry.Remove(providerType, descriptorToRemove);
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ public class ScheduleActivityExecutionContextTests(ITestOutputHelper testOutputH
|
|||
var workflowGraphBuilder = _serviceProvider.GetRequiredService<IWorkflowGraphBuilder>();
|
||||
var workflowGraph = await workflowGraphBuilder.BuildAsync(workflow);
|
||||
var workflowExecutionContext = await WorkflowExecutionContext.CreateAsync(_serviceProvider, workflowGraph, "test");
|
||||
var activityExecutionContext = workflowExecutionContext.CreateActivityExecutionContext(writeLineA);
|
||||
var activityExecutionContext = await workflowExecutionContext.CreateActivityExecutionContext(writeLineA);
|
||||
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => activityExecutionContext.ScheduleActivityAsync(writeLineB).AsTask());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue