diff --git a/src/modules/Elsa.Dsl/Contracts/IFunctionActivityRegistry.cs b/src/modules/Elsa.Dsl/Contracts/IFunctionActivityRegistry.cs index a2af20905..0b9f2001b 100644 --- a/src/modules/Elsa.Dsl/Contracts/IFunctionActivityRegistry.cs +++ b/src/modules/Elsa.Dsl/Contracts/IFunctionActivityRegistry.cs @@ -22,12 +22,12 @@ public interface IFunctionActivityRegistry /// /// The descriptor that describes the function. void RegisterFunction(FunctionActivityDescriptor descriptor); - + /// /// Resolves a function to an activity that can be invoked from a DSL script. /// /// The name of the function. /// The arguments that are passed to the function. /// An activity that can be invoked from a DSL script. - IActivity ResolveFunction(string functionName, IEnumerable? arguments = default); + Task ResolveFunction(string functionName, IEnumerable? arguments = default); } \ No newline at end of file diff --git a/src/modules/Elsa.Dsl/Interpreters/WorkflowDefinitionBuilderInterpreter/VisitFunction.cs b/src/modules/Elsa.Dsl/Interpreters/WorkflowDefinitionBuilderInterpreter/VisitFunction.cs index 8d195e34b..b68beb4c9 100644 --- a/src/modules/Elsa.Dsl/Interpreters/WorkflowDefinitionBuilderInterpreter/VisitFunction.cs +++ b/src/modules/Elsa.Dsl/Interpreters/WorkflowDefinitionBuilderInterpreter/VisitFunction.cs @@ -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; diff --git a/src/modules/Elsa.Dsl/Interpreters/WorkflowDefinitionBuilderInterpreter/VisitObject.cs b/src/modules/Elsa.Dsl/Interpreters/WorkflowDefinitionBuilderInterpreter/VisitObject.cs index 19edf7c5f..50cc73d60 100644 --- a/src/modules/Elsa.Dsl/Interpreters/WorkflowDefinitionBuilderInterpreter/VisitObject.cs +++ b/src/modules/Elsa.Dsl/Interpreters/WorkflowDefinitionBuilderInterpreter/VisitObject.cs @@ -29,7 +29,7 @@ public partial class WorkflowDefinitionBuilderInterpreter /// 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 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) { diff --git a/src/modules/Elsa.Dsl/Interpreters/WorkflowDefinitionBuilderInterpreter/WorkflowDefinitionBuilderInterpreter.cs b/src/modules/Elsa.Dsl/Interpreters/WorkflowDefinitionBuilderInterpreter/WorkflowDefinitionBuilderInterpreter.cs index 1474c14f9..ce0276566 100644 --- a/src/modules/Elsa.Dsl/Interpreters/WorkflowDefinitionBuilderInterpreter/WorkflowDefinitionBuilderInterpreter.cs +++ b/src/modules/Elsa.Dsl/Interpreters/WorkflowDefinitionBuilderInterpreter/WorkflowDefinitionBuilderInterpreter.cs @@ -9,7 +9,7 @@ namespace Elsa.Dsl.Interpreters; public partial class WorkflowDefinitionBuilderInterpreter : ElsaParserBaseVisitor { private readonly ITypeSystem _typeSystem; - private readonly IActivityRegistry _activityRegistry; + private readonly IActivityRegistryLookupService _activityRegistryLookup; private readonly IFunctionActivityRegistry _functionActivityRegistry; private readonly IWorkflowBuilder _workflowBuilder; private readonly ParseTreeProperty _object = new(); @@ -22,12 +22,12 @@ public partial class WorkflowDefinitionBuilderInterpreter : ElsaParserBaseVisito /// public WorkflowDefinitionBuilderInterpreter( ITypeSystem typeSystem, - IActivityRegistry activityRegistry, + IActivityRegistryLookupService activityRegistryLookup, IFunctionActivityRegistry functionActivityRegistry, IWorkflowBuilderFactory workflowBuilderFactory) { _typeSystem = typeSystem; - _activityRegistry = activityRegistry; + _activityRegistryLookup = activityRegistryLookup; _functionActivityRegistry = functionActivityRegistry; _workflowBuilder = workflowBuilderFactory.CreateBuilder(); } diff --git a/src/modules/Elsa.Dsl/Services/DslEngine.cs b/src/modules/Elsa.Dsl/Services/DslEngine.cs index 91e0e2220..bcef7a99d 100644 --- a/src/modules/Elsa.Dsl/Services/DslEngine.cs +++ b/src/modules/Elsa.Dsl/Services/DslEngine.cs @@ -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 /// 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); diff --git a/src/modules/Elsa.Dsl/Services/FunctionActivityRegistry.cs b/src/modules/Elsa.Dsl/Services/FunctionActivityRegistry.cs index 696e6dc72..eebd83277 100644 --- a/src/modules/Elsa.Dsl/Services/FunctionActivityRegistry.cs +++ b/src/modules/Elsa.Dsl/Services/FunctionActivityRegistry.cs @@ -12,15 +12,15 @@ namespace Elsa.Dsl.Services; /// public class FunctionActivityRegistry : IFunctionActivityRegistry { - private readonly IActivityRegistry _activityRegistry; + private readonly IActivityRegistryLookupService _activityRegistryLookup; private readonly IDictionary _dictionary = new Dictionary(); /// /// Creates a new instance of the class. /// - public FunctionActivityRegistry(IActivityRegistry activityRegistry) + public FunctionActivityRegistry(IActivityRegistryLookupService activityRegistryLookup) { - _activityRegistry = activityRegistry; + _activityRegistryLookup = activityRegistryLookup; } /// @@ -37,12 +37,12 @@ public class FunctionActivityRegistry : IFunctionActivityRegistry } /// - public IActivity ResolveFunction(string functionName, IEnumerable? arguments = default) + public async Task ResolveFunction(string functionName, IEnumerable? 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}"); diff --git a/src/modules/Elsa.JavaScript/Services/JintJavaScriptEvaluator.cs b/src/modules/Elsa.JavaScript/Services/JintJavaScriptEvaluator.cs index 90013a0b2..36a6f3a16 100644 --- a/src/modules/Elsa.JavaScript/Services/JintJavaScriptEvaluator.cs +++ b/src/modules/Elsa.JavaScript/Services/JintJavaScriptEvaluator.cs @@ -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)(() => context.GetOutput(activityOutput.ActivityId, outputName))); } diff --git a/src/modules/Elsa.JavaScript/TypeDefinitions/Providers/ActivityOutputFunctionsDefinitionProvider.cs b/src/modules/Elsa.JavaScript/TypeDefinitions/Providers/ActivityOutputFunctionsDefinitionProvider.cs index 0588f5dab..fb52ac4c9 100644 --- a/src/modules/Elsa.JavaScript/TypeDefinitions/Providers/ActivityOutputFunctionsDefinitionProvider.cs +++ b/src/modules/Elsa.JavaScript/TypeDefinitions/Providers/ActivityOutputFunctionsDefinitionProvider.cs @@ -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(); - foreach (var (activity, activityDescriptor) in activitiesWithOutputs) + await foreach (var (activity, activityDescriptor) in activitiesWithOutputs) { definitions.AddRange(from output in activityDescriptor.Outputs select output.Name.Pascalize() diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptorOptions/Get/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptorOptions/Get/Endpoint.cs index 100ac9593..c0601f12e 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptorOptions/Get/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptorOptions/Get/Endpoint.cs @@ -8,14 +8,14 @@ namespace Elsa.Workflows.Api.Endpoints.ActivityDescriptorOptions.Get; internal class Get : ElsaEndpoint { private readonly IServiceProvider _serviceProvider; - private readonly IActivityRegistry _registry; + private readonly IActivityRegistryLookupService _registryLookup; private readonly IPropertyUIHandlerResolver _optionsResolver; /// - 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 /// 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); diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptors/Get/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptors/Get/Endpoint.cs index 6ef776657..459cf1635 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptors/Get/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptors/Get/Endpoint.cs @@ -8,12 +8,12 @@ namespace Elsa.Workflows.Api.Endpoints.ActivityDescriptors.Get; [PublicAPI] internal class Get : ElsaEndpoint { - private readonly IActivityRegistry _registry; + private readonly IActivityRegistryLookupService _registryLookup; /// - public Get(IActivityRegistry registry) + public Get(IActivityRegistryLookupService registryLookup) { - _registry = registry; + _registryLookup = registryLookup; } /// @@ -26,7 +26,7 @@ internal class Get : ElsaEndpoint /// 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); diff --git a/src/modules/Elsa.Workflows.Core/Builders/WorkflowBuilder.cs b/src/modules/Elsa.Workflows.Core/Builders/WorkflowBuilder.cs index 65e1145e6..34f69d11c 100644 --- a/src/modules/Elsa.Workflows.Core/Builders/WorkflowBuilder.cs +++ b/src/modules/Elsa.Workflows.Core/Builders/WorkflowBuilder.cs @@ -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(); diff --git a/src/modules/Elsa.Workflows.Core/Contexts/WorkflowExecutionContext.cs b/src/modules/Elsa.Workflows.Core/Contexts/WorkflowExecutionContext.cs index 1af3d2301..c8d77efbd 100644 --- a/src/modules/Elsa.Workflows.Core/Contexts/WorkflowExecutionContext.cs +++ b/src/modules/Elsa.Workflows.Core/Contexts/WorkflowExecutionContext.cs @@ -60,6 +60,7 @@ public partial class WorkflowExecutionContext : IExecutionContext ServiceProvider = serviceProvider; SystemClock = serviceProvider.GetRequiredService(); ActivityRegistry = serviceProvider.GetRequiredService(); + ActivityRegistryLookup = serviceProvider.GetRequiredService(); _hasher = serviceProvider.GetRequiredService(); SubStatus = WorkflowSubStatus.Pending; Id = id; @@ -152,7 +153,7 @@ public partial class WorkflowExecutionContext : IExecutionContext cancellationTokens); var workflowStateExtractor = serviceProvider.GetRequiredService(); - workflowStateExtractor.Apply(workflowExecutionContext, workflowState); + await workflowStateExtractor.Apply(workflowExecutionContext, workflowState); return workflowExecutionContext; } @@ -228,6 +229,11 @@ public partial class WorkflowExecutionContext : IExecutionContext /// public IActivityRegistry ActivityRegistry { get; } + /// + /// Gets the . + /// + public IActivityRegistryLookupService ActivityRegistryLookup { get; } + /// /// Gets the workflow graph. /// @@ -572,9 +578,9 @@ public partial class WorkflowExecutionContext : IExecutionContext /// /// Creates a new for the specified activity. /// - public ActivityExecutionContext CreateActivityExecutionContext(IActivity activity, ActivityInvocationOptions? options = default) + public async Task 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; diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IActivityRegistry.cs b/src/modules/Elsa.Workflows.Core/Contracts/IActivityRegistry.cs index 0e91e44ec..c3ed1630f 100644 --- a/src/modules/Elsa.Workflows.Core/Contracts/IActivityRegistry.cs +++ b/src/modules/Elsa.Workflows.Core/Contracts/IActivityRegistry.cs @@ -14,13 +14,6 @@ public interface IActivityRegistry : IActivityProvider /// The activity descriptor to add. void Add(Type providerType, ActivityDescriptor descriptor); - /// - /// Adds multiple activity descriptors to the registry. - /// - /// The type of the activity provider. - /// The activity descriptors to add. - void AddMany(Type providerType, IEnumerable descriptors); - /// /// Removes an activity descriptor from the registry. /// @@ -28,17 +21,6 @@ public interface IActivityRegistry : IActivityProvider /// The activity descriptor to remove. void Remove(Type providerType, ActivityDescriptor descriptor); - /// - /// Clears all activity descriptors from the registry. - /// - void Clear(); - - /// - /// Clears all activity descriptors provided by the specified provider. - /// - /// The type of the activity provider. - void ClearProvider(Type providerType); - /// /// Returns all activity descriptors in the registry. /// @@ -100,4 +82,12 @@ public interface IActivityRegistry : IActivityProvider /// The activity types to register. /// An optional cancellation token. Task RegisterAsync(IEnumerable activityTypes, CancellationToken cancellationToken = default); + + /// + /// Refreshes the activity descriptors in the registry by querying the specified activity providers. + /// + /// The activity providers used to retrieve the descriptors. + /// The cancellation token. + /// A task representing the asynchronous operation. + Task RefreshDescriptors(IEnumerable activityProviders, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IActivityRegistryLookupService.cs b/src/modules/Elsa.Workflows.Core/Contracts/IActivityRegistryLookupService.cs new file mode 100644 index 000000000..93f02136a --- /dev/null +++ b/src/modules/Elsa.Workflows.Core/Contracts/IActivityRegistryLookupService.cs @@ -0,0 +1,38 @@ +using Elsa.Workflows.Models; + +namespace Elsa.Workflows.Contracts; + +/// +/// Represents a service for looking up activity descriptors. +/// +public interface IActivityRegistryLookupService +{ + /// + /// Returns the activity descriptor for the specified activity type. + /// + /// The activity type. + /// The activity descriptor for the specified activity type. + Task Find(string type); + + /// + /// Returns the activity descriptor for the specified activity type and version. + /// + /// The activity type. + /// The activity version. + /// The activity descriptor for the specified activity type and version. + Task Find(string type, int version); + + /// + /// Returns the activity descriptor matching the specified predicate. + /// + /// The predicate to match. + /// The activity descriptor matching the specified predicate. + Task Find(Func predicate); + + /// + /// Returns all activity descriptors matching the specified predicate. + /// + /// The predicate to match. + /// All activity descriptors matching the specified predicate. + IEnumerable FindMany(Func predicate); +} \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IIdentityGraphService.cs b/src/modules/Elsa.Workflows.Core/Contracts/IIdentityGraphService.cs index f462ed834..4e758dc99 100644 --- a/src/modules/Elsa.Workflows.Core/Contracts/IIdentityGraphService.cs +++ b/src/modules/Elsa.Workflows.Core/Contracts/IIdentityGraphService.cs @@ -21,17 +21,17 @@ public interface IIdentityGraphService /// /// Assign unique identities tot the specified graph. /// - void AssignIdentities(ActivityNode root); + Task AssignIdentities(ActivityNode root); /// /// Assign unique identities tot the specified flattened list of s. /// - void AssignIdentities(ICollection flattenedList); + Task AssignIdentities(ICollection flattenedList); /// /// Assign unique identities to input and output properties of the specified graph. /// - void AssignInputOutputs(IActivity activity); + Task AssignInputOutputs(IActivity activity); /// /// Assign unique identities to variables of the specified . diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowStateExtractor.cs b/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowStateExtractor.cs index 6dd6b4f47..0ef1a8dc1 100644 --- a/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowStateExtractor.cs +++ b/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowStateExtractor.cs @@ -13,12 +13,12 @@ public interface IWorkflowStateExtractor /// The workflow execution context to map. /// The mapped workflow state. WorkflowState Extract(WorkflowExecutionContext workflowExecutionContext); - + /// /// Applies workflow state to a workflow execution context. /// /// The workflow execution context to map onto. /// The workflow state to apply. /// The updated workflow execution context. - WorkflowExecutionContext Apply(WorkflowExecutionContext workflowExecutionContext, WorkflowState state); + Task Apply(WorkflowExecutionContext workflowExecutionContext, WorkflowState state); } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Core/Extensions/ActivityExecutionContextExtensions.cs b/src/modules/Elsa.Workflows.Core/Extensions/ActivityExecutionContextExtensions.cs index d69308d04..4e88b69ac 100644 --- a/src/modules/Elsa.Workflows.Core/Extensions/ActivityExecutionContextExtensions.cs +++ b/src/modules/Elsa.Workflows.Core/Extensions/ActivityExecutionContextExtensions.cs @@ -138,24 +138,24 @@ public static class ActivityExecutionContextExtensions /// /// Evaluates a specific input property of the activity. /// - public static Task EvaluateInputPropertyAsync(this ActivityExecutionContext context, string inputName) + public static async Task EvaluateInputPropertyAsync(this ActivityExecutionContext context, string inputName) { var activity = context.Activity; - var activityRegistry = context.GetRequiredService(); - var activityDescriptor = activityRegistry.Find(activity.Type) ?? throw new Exception("Activity descriptor not found"); + var activityRegistryLookup = context.GetRequiredService(); + 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); } /// /// Returns a set of tuples containing the activity and its descriptor for all activities with outputs. /// /// The being extended. - 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(); + var activityRegistry = workflowExecutionContext.GetRequiredService(); var activitiesWithOutputs = containedNodes.GetActivitiesWithOutputs(activityRegistry); - foreach (var (activity, activityDescriptor) in activitiesWithOutputs) + await foreach (var (activity, activityDescriptor) in activitiesWithOutputs) yield return (activity, activityDescriptor); } /// /// Returns a set of tuples containing the activity and its descriptor for all activities with outputs. /// - public static IEnumerable<(IActivity Activity, ActivityDescriptor ActivityDescriptor)> GetActivitiesWithOutputs(this IEnumerable nodes, IActivityRegistry activityRegistry) + public static async IAsyncEnumerable<(IActivity activity, ActivityDescriptor activityDescriptor)> GetActivitiesWithOutputs(this IEnumerable 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); + } } /// diff --git a/src/modules/Elsa.Workflows.Core/Extensions/ActivityRegistryExtensions.cs b/src/modules/Elsa.Workflows.Core/Extensions/ActivityRegistryExtensions.cs index 6f55f20ab..75a99b2ff 100644 --- a/src/modules/Elsa.Workflows.Core/Extensions/ActivityRegistryExtensions.cs +++ b/src/modules/Elsa.Workflows.Core/Extensions/ActivityRegistryExtensions.cs @@ -13,7 +13,7 @@ public static class ActivityRegistryExtensions /// /// Finds the activity descriptor for the specified activity. /// - public static ActivityDescriptor? Find(this IActivityRegistry activityRegistry, IActivity activity) => activityRegistry.Find(activity.Type, activity.Version); + public static Task Find(this IActivityRegistryLookupService activityRegistry, IActivity activity) => activityRegistry.Find(activity.Type, activity.Version); /// /// Finds the activity descriptor for the specified activity type. diff --git a/src/modules/Elsa.Workflows.Core/Extensions/ExpressionExecutionContextExtensions.cs b/src/modules/Elsa.Workflows.Core/Extensions/ExpressionExecutionContextExtensions.cs index 8edbdb55c..4ec3e1f0c 100644 --- a/src/modules/Elsa.Workflows.Core/Extensions/ExpressionExecutionContextExtensions.cs +++ b/src/modules/Elsa.Workflows.Core/Extensions/ExpressionExecutionContextExtensions.cs @@ -434,7 +434,7 @@ public static class ExpressionExecutionContextExtensions /// /// Returns all activity outputs. /// - public static IEnumerable GetActivityOutputs(this ExpressionExecutionContext context) + public static async IAsyncEnumerable 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; diff --git a/src/modules/Elsa.Workflows.Core/Features/WorkflowsFeature.cs b/src/modules/Elsa.Workflows.Core/Features/WorkflowsFeature.cs index 1135c85e2..2b8f36931 100644 --- a/src/modules/Elsa.Workflows.Core/Features/WorkflowsFeature.cs +++ b/src/modules/Elsa.Workflows.Core/Features/WorkflowsFeature.cs @@ -136,6 +136,7 @@ public class WorkflowsFeature : FeatureBase .AddScoped(sp => ActivatorUtilities.CreateInstance(sp)) .AddSingleton() .AddSingleton() + .AddScoped() .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/src/modules/Elsa.Workflows.Core/Services/ActivityInvoker.cs b/src/modules/Elsa.Workflows.Core/Services/ActivityInvoker.cs index 343f43f5e..fc33def90 100644 --- a/src/modules/Elsa.Workflows.Core/Services/ActivityInvoker.cs +++ b/src/modules/Elsa.Workflows.Core/Services/ActivityInvoker.cs @@ -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); diff --git a/src/modules/Elsa.Workflows.Core/Services/ActivityRegistry.cs b/src/modules/Elsa.Workflows.Core/Services/ActivityRegistry.cs index ccfa3ec69..b6fb1a6e8 100644 --- a/src/modules/Elsa.Workflows.Core/Services/ActivityRegistry.cs +++ b/src/modules/Elsa.Workflows.Core/Services/ActivityRegistry.cs @@ -7,37 +7,15 @@ using Microsoft.Extensions.Logging; namespace Elsa.Workflows.Services; /// -public class ActivityRegistry : IActivityRegistry +public class ActivityRegistry(IActivityDescriber activityDescriber, IEnumerable modifiers, ILogger logger) : IActivityRegistry { - private readonly IActivityDescriber _activityDescriber; - private readonly IEnumerable _modifiers; - private readonly ILogger _logger; private readonly ISet _manualActivityDescriptors = new HashSet(); - private readonly ConcurrentDictionary> _providedActivityDescriptors = new(); - private readonly ConcurrentDictionary<(string Type, int Version), ActivityDescriptor> _activityDescriptors = new(); - - /// - /// Initializes a new instance of the class. - /// - public ActivityRegistry(IActivityDescriber activityDescriber, IEnumerable modifiers, ILogger logger) - { - _activityDescriber = activityDescriber; - _modifiers = modifiers; - _logger = logger; - } + private ConcurrentDictionary> _providedActivityDescriptors = new(); + private ConcurrentDictionary<(string Type, int Version), ActivityDescriptor> _activityDescriptors = new(); /// public void Add(Type providerType, ActivityDescriptor descriptor) => Add(descriptor, GetOrCreateDescriptors(providerType)); - /// - public void AddMany(Type providerType, IEnumerable descriptors) - { - var target = GetOrCreateDescriptors(providerType); - - foreach (var descriptor in descriptors) - Add(descriptor, target); - } - /// public void Remove(Type providerType, ActivityDescriptor descriptor) { @@ -45,24 +23,6 @@ public class ActivityRegistry : IActivityRegistry _activityDescriptors.Remove((descriptor.TypeName, descriptor.Version), out _); } - /// - public void Clear() - { - _activityDescriptors.Clear(); - _providedActivityDescriptors.Clear(); - } - - /// - 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 _); - } - /// public IEnumerable 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); } + + /// + public ValueTask> GetDescriptorsAsync(CancellationToken cancellationToken = default) => new(_manualActivityDescriptors); + public async Task RefreshDescriptors(IEnumerable activityProviders, CancellationToken cancellationToken = default) + { + var providersDictionary = new ConcurrentDictionary>(); + 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(); + 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 target) { - foreach (var modifier in _modifiers) + Add(descriptor, _activityDescriptors, target); + } + + private void Add(ActivityDescriptor descriptor, ConcurrentDictionary<(string Type, int Version), ActivityDescriptor> activityDescriptors, ICollection 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 GetOrCreateDescriptors(Type provider) @@ -136,7 +123,4 @@ public class ActivityRegistry : IActivityRegistry return descriptors; } - - /// - public ValueTask> GetDescriptorsAsync(CancellationToken cancellationToken = default) => new(_manualActivityDescriptors); } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Core/Services/ActivityRegistryLookupService.cs b/src/modules/Elsa.Workflows.Core/Services/ActivityRegistryLookupService.cs new file mode 100644 index 000000000..3b5883ff6 --- /dev/null +++ b/src/modules/Elsa.Workflows.Core/Services/ActivityRegistryLookupService.cs @@ -0,0 +1,44 @@ +using Elsa.Workflows.Contracts; +using Elsa.Workflows.Models; + +namespace Elsa.Workflows.Services; + +/// +/// Represents a service used to lookup activity descriptors in the activity registry. +/// +public class ActivityRegistryLookupService(IActivityRegistry activityRegistry, IEnumerable providers) : IActivityRegistryLookupService +{ + /// + public Task Find(string type) + { + return Find(() => activityRegistry.Find(type)); + } + + /// + public Task Find(string type, int version) + { + return Find(() => activityRegistry.Find(type, version)); + } + + /// + public Task Find(Func predicate) + { + return Find(() => activityRegistry.Find(predicate)); + } + + /// + public IEnumerable FindMany(Func predicate) + { + return activityRegistry.FindMany(predicate); + } + + private async Task Find(Func findPredicate) + { + var descriptor = findPredicate.Invoke(); + if (descriptor is not null) + return descriptor; + + await activityRegistry.RefreshDescriptors(providers); + return findPredicate.Invoke(); + } +} \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Core/Services/IdentityGraphService.cs b/src/modules/Elsa.Workflows.Core/Services/IdentityGraphService.cs index 8deaa2ea0..7343aa8ab 100644 --- a/src/modules/Elsa.Workflows.Core/Services/IdentityGraphService.cs +++ b/src/modules/Elsa.Workflows.Core/Services/IdentityGraphService.cs @@ -10,15 +10,15 @@ namespace Elsa.Workflows.Services; public class IdentityGraphService : IIdentityGraphService { private readonly IActivityVisitor _activityVisitor; - private readonly IActivityRegistry _activityRegistry; + private readonly IActivityRegistryLookupService _activityRegistryLookup; /// /// Constructor. /// - public IdentityGraphService(IActivityVisitor activityVisitor, IActivityRegistry activityRegistry) + public IdentityGraphService(IActivityVisitor activityVisitor, IActivityRegistryLookupService activityRegistryLookup) { _activityVisitor = activityVisitor; - _activityRegistry = activityRegistry; + _activityRegistryLookup = activityRegistryLookup; } /// @@ -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); } /// - public void AssignIdentities(ActivityNode root) => AssignIdentities(root.Flatten().ToList()); + public Task AssignIdentities(ActivityNode root) => AssignIdentities(root.Flatten().ToList()); /// - public void AssignIdentities(ICollection flattenedList) + public async Task AssignIdentities(ICollection flattenedList) { var identityCounters = new Dictionary(); @@ -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 } /// - 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) diff --git a/src/modules/Elsa.Workflows.Core/Services/WorkflowGraphBuilder.cs b/src/modules/Elsa.Workflows.Core/Services/WorkflowGraphBuilder.cs index e08aa480b..62c366213 100644 --- a/src/modules/Elsa.Workflows.Core/Services/WorkflowGraphBuilder.cs +++ b/src/modules/Elsa.Workflows.Core/Services/WorkflowGraphBuilder.cs @@ -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); } } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Core/Services/WorkflowStateExtractor.cs b/src/modules/Elsa.Workflows.Core/Services/WorkflowStateExtractor.cs index eaffc63ab..2e0cee34b 100644 --- a/src/modules/Elsa.Workflows.Core/Services/WorkflowStateExtractor.cs +++ b/src/modules/Elsa.Workflows.Core/Services/WorkflowStateExtractor.cs @@ -41,7 +41,7 @@ public class WorkflowStateExtractor : IWorkflowStateExtractor } /// - public WorkflowExecutionContext Apply(WorkflowExecutionContext workflowExecutionContext, WorkflowState state) + public async Task 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 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(); diff --git a/src/modules/Elsa.Workflows.Management/Activities/WorkflowDefinitionActivity/WorkflowDefinitionActivity.cs b/src/modules/Elsa.Workflows.Management/Activities/WorkflowDefinitionActivity/WorkflowDefinitionActivity.cs index 950ce04fc..5f7d2b1e2 100644 --- a/src/modules/Elsa.Workflows.Management/Activities/WorkflowDefinitionActivity/WorkflowDefinitionActivity.cs +++ b/src/modules/Elsa.Workflows.Management/Activities/WorkflowDefinitionActivity/WorkflowDefinitionActivity.cs @@ -45,7 +45,7 @@ public class WorkflowDefinitionActivity : Composite, IInitializable /// 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(); - 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 configureVariable) @@ -165,10 +165,10 @@ public class WorkflowDefinitionActivity : Composite, IInitializable return workflowGraph; } - private ActivityDescriptor? FindActivityDescriptor(IServiceProvider serviceProvider) + private async Task FindActivityDescriptor(IServiceProvider serviceProvider) { - var activityRegistry = serviceProvider.GetRequiredService(); - return activityRegistry.Find(Type, Version) ?? activityRegistry.Find(Type); + var activityRegistryLookup = serviceProvider.GetRequiredService(); + 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) { diff --git a/src/modules/Elsa.Workflows.Management/Services/ActivityRegistryPopulator.cs b/src/modules/Elsa.Workflows.Management/Services/ActivityRegistryPopulator.cs index 5c47899f9..a7836f5ac 100644 --- a/src/modules/Elsa.Workflows.Management/Services/ActivityRegistryPopulator.cs +++ b/src/modules/Elsa.Workflows.Management/Services/ActivityRegistryPopulator.cs @@ -7,41 +7,18 @@ namespace Elsa.Workflows.Management.Services; /// /// Populates the with descriptors provided by s. /// -public class ActivityRegistryPopulator : IActivityRegistryPopulator +public class ActivityRegistryPopulator(IEnumerable providers, IActivityRegistry registry) : IActivityRegistryPopulator { - private readonly IEnumerable _providers; - private readonly IActivityRegistry _registry; - - /// - /// Constructor. - /// - public ActivityRegistryPopulator(IEnumerable providers, IActivityRegistry registry) - { - _providers = providers; - _registry = registry; - } - /// public async Task PopulateRegistryAsync(CancellationToken cancellationToken) { - _registry.Clear(); - - foreach (var provider in _providers) - await PopulateRegistryAsync(provider, cancellationToken); - } - - /// - 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); } /// 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); } /// 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); } } /// 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); } } \ No newline at end of file diff --git a/test/unit/Elsa.Workflows.Core.UnitTests/ScheduleActivityExecutionContextTests.cs b/test/unit/Elsa.Workflows.Core.UnitTests/ScheduleActivityExecutionContextTests.cs index 3c7f48fd1..91a7258f0 100644 --- a/test/unit/Elsa.Workflows.Core.UnitTests/ScheduleActivityExecutionContextTests.cs +++ b/test/unit/Elsa.Workflows.Core.UnitTests/ScheduleActivityExecutionContextTests.cs @@ -23,7 +23,7 @@ public class ScheduleActivityExecutionContextTests(ITestOutputHelper testOutputH var workflowGraphBuilder = _serviceProvider.GetRequiredService(); 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(() => activityExecutionContext.ScheduleActivityAsync(writeLineB).AsTask()); }