From 6b7caddca84189eac1c517801ff57ee963430792 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Mon, 7 Mar 2022 12:01:27 +0100 Subject: [PATCH] Refactor triggers --- Elsa.sln.DotSettings | 1 + .../Elsa.Core/Activities/Primitives/Event.cs | 2 +- src/core/Elsa.Core/Contracts/IActivity.cs | 28 +++++- ...rializer.cs => IBookmarkDataSerializer.cs} | 2 +- .../Elsa.Core/Contracts/IEventGenerator.cs | 12 +++ src/core/Elsa.Core/Contracts/INode.cs | 8 -- src/core/Elsa.Core/Contracts/ITrigger.cs | 17 +--- .../Elsa.Core/Extensions/NodeExtensions.cs | 15 ---- src/core/Elsa.Core/Models/Activity.cs | 12 ++- .../Models/ActivityExecutionContext.cs | 23 +++-- src/core/Elsa.Core/Models/Bookmark.cs | 2 +- src/core/Elsa.Core/Models/EventGenerator.cs | 14 +++ .../Models/ExpressionExecutionContext.cs | 4 +- src/core/Elsa.Core/Models/Trigger.cs | 21 +++-- .../Models/TriggerIndexingContext.cs | 4 +- src/core/Elsa.Core/Models/TriggerMode.cs | 17 ---- .../Models/WorkflowIndexingContext.cs | 4 +- .../Components/ActivityInvokerMiddleware.cs | 2 +- .../Elsa.Core/Services/ActivityInvoker.cs | 2 +- ...erializer.cs => BookmarkDataSerializer.cs} | 4 +- src/core/Elsa.Core/Services/Hasher.cs | 8 +- .../Services/IdentityGraphService.cs | 2 +- .../Services/WorkflowStateSerializer.cs | 5 +- .../Contracts/ITriggerDescriber.cs | 8 -- .../Contracts/ITriggerFactory.cs | 9 -- .../Contracts/ITriggerProvider.cs | 8 -- .../Contracts/ITriggerRegistry.cs | 15 ---- .../Contracts/ITriggerRegistryPopulator.cs | 6 -- .../Extensions/ServiceCollectionExtensions.cs | 5 -- .../Models/TriggerDescriptor.cs | 2 +- .../Providers/TypedTriggerProvider.cs | 35 -------- .../Converters/FlowchartJsonConverter.cs | 2 +- .../Converters/TriggerJsonConverter.cs | 52 ----------- .../Converters/TriggerJsonConverterFactory.cs | 24 ----- .../WorkflowSerializerOptionsProvider.cs | 1 - .../Services/ActivityDescriber.cs | 4 +- .../Services/TriggerDescriber.cs | 83 ----------------- .../Services/TriggerFactory.cs | 15 ---- .../Services/TriggerRegistry.cs | 58 ------------ .../Services/TriggerRegistryPopulator.cs | 27 ------ .../Extensions/ServiceCollectionExtensions.cs | 3 +- src/dsl/Elsa.Dsl/AssemblyInfo.cs | 2 +- .../Extensions/TypeSystemExtensions.cs | 2 +- .../Activities/MessageReceived.cs | 9 +- .../Handlers/UpdateWorkers.cs | 12 +-- .../{HttpTrigger.cs => HttpEndpoint.cs} | 12 +-- .../Middleware/HttpTriggerMiddleware.cs | 4 +- ...pTriggerPayload.cs => HttpBookmarkData.cs} | 4 +- .../Activities/Delay.cs | 2 +- .../Services/WorkflowBookmarkScheduler.cs | 2 +- .../Services/WorkflowTriggerScheduler.cs | 2 +- .../Elsa.Modules.Scheduling/Triggers/Timer.cs | 6 +- .../Entities/WorkflowBookmark.cs | 6 +- .../Entities/WorkflowTrigger.cs | 2 +- .../Requests/FindWorkflowTriggersByName.cs | 2 +- .../Actors/WorkflowOperatorActor.cs | 2 +- .../Services/ProtoActorWorkflowInvoker.cs | 2 +- .../HostedServices/RegisterDescriptors.cs | 18 +--- .../ResumeWorkflowInstructionInterpreter.cs | 2 +- .../Elsa.Runtime/Services/TriggerIndexer.cs | 89 +++++++++++++------ .../aspnet/Elsa.Samples.Web1/Program.cs | 2 +- .../Workflows/ForkedHttpWorkflow.cs | 6 +- .../Workflows/HttpWorkflow.cs | 4 +- .../aspnet/Elsa.Samples.Web2/Program.cs | 5 +- .../console/Elsa.Samples.Console2/Program.cs | 2 +- 65 files changed, 228 insertions(+), 537 deletions(-) rename src/core/Elsa.Core/Contracts/{IPayloadSerializer.cs => IBookmarkDataSerializer.cs} (76%) create mode 100644 src/core/Elsa.Core/Contracts/IEventGenerator.cs delete mode 100644 src/core/Elsa.Core/Contracts/INode.cs create mode 100644 src/core/Elsa.Core/Models/EventGenerator.cs delete mode 100644 src/core/Elsa.Core/Models/TriggerMode.cs rename src/core/Elsa.Core/Services/{PayloadSerializer.cs => BookmarkDataSerializer.cs} (85%) delete mode 100644 src/core/Elsa.Management/Contracts/ITriggerDescriber.cs delete mode 100644 src/core/Elsa.Management/Contracts/ITriggerFactory.cs delete mode 100644 src/core/Elsa.Management/Contracts/ITriggerProvider.cs delete mode 100644 src/core/Elsa.Management/Contracts/ITriggerRegistry.cs delete mode 100644 src/core/Elsa.Management/Contracts/ITriggerRegistryPopulator.cs delete mode 100644 src/core/Elsa.Management/Providers/TypedTriggerProvider.cs delete mode 100644 src/core/Elsa.Management/Serialization/Converters/TriggerJsonConverter.cs delete mode 100644 src/core/Elsa.Management/Serialization/Converters/TriggerJsonConverterFactory.cs delete mode 100644 src/core/Elsa.Management/Services/TriggerDescriber.cs delete mode 100644 src/core/Elsa.Management/Services/TriggerFactory.cs delete mode 100644 src/core/Elsa.Management/Services/TriggerRegistry.cs delete mode 100644 src/core/Elsa.Management/Services/TriggerRegistryPopulator.cs rename src/modules/Elsa.Modules.Http/Activities/{HttpTrigger.cs => HttpEndpoint.cs} (58%) rename src/modules/Elsa.Modules.Http/Models/{HttpTriggerPayload.cs => HttpBookmarkData.cs} (82%) diff --git a/Elsa.sln.DotSettings b/Elsa.sln.DotSettings index 05eadb4ff..f5da10727 100644 --- a/Elsa.sln.DotSettings +++ b/Elsa.sln.DotSettings @@ -2,6 +2,7 @@ True True True + True True True True diff --git a/src/core/Elsa.Core/Activities/Primitives/Event.cs b/src/core/Elsa.Core/Activities/Primitives/Event.cs index 187cdd953..37ccad172 100644 --- a/src/core/Elsa.Core/Activities/Primitives/Event.cs +++ b/src/core/Elsa.Core/Activities/Primitives/Event.cs @@ -35,6 +35,6 @@ public class Event : Activity var hasher = context.GetRequiredService(); var eventName = context.Get(EventName)!; var hash = hasher.Hash(eventName); - context.SetBookmark(hash); + context.CreateBookmark(hash); } } \ No newline at end of file diff --git a/src/core/Elsa.Core/Contracts/IActivity.cs b/src/core/Elsa.Core/Contracts/IActivity.cs index a103015fd..0c87c3df8 100644 --- a/src/core/Elsa.Core/Contracts/IActivity.cs +++ b/src/core/Elsa.Core/Contracts/IActivity.cs @@ -2,7 +2,33 @@ using Elsa.Models; namespace Elsa.Contracts; -public interface IActivity : INode +/// +/// Represents an activity, which is an atomic unit of operation within a workflow. +/// +public interface IActivity { + /// + /// An identifier that is unique within the workflow. + /// + string Id { get; set; } + + /// + /// The logical type name of the activity. + /// + string TypeName { get; set; } + + /// + /// A value indicating whether this activity can start instances of the workflow it is a part of. + /// + public bool CanStartWorkflow { get; set; } + + /// + /// Can contain application-specific information about this activity. + /// + IDictionary Metadata { get; set; } + + /// + /// Invoked when the activity executes. + /// ValueTask ExecuteAsync(ActivityExecutionContext context); } \ No newline at end of file diff --git a/src/core/Elsa.Core/Contracts/IPayloadSerializer.cs b/src/core/Elsa.Core/Contracts/IBookmarkDataSerializer.cs similarity index 76% rename from src/core/Elsa.Core/Contracts/IPayloadSerializer.cs rename to src/core/Elsa.Core/Contracts/IBookmarkDataSerializer.cs index 2b722d239..b6e574c8e 100644 --- a/src/core/Elsa.Core/Contracts/IPayloadSerializer.cs +++ b/src/core/Elsa.Core/Contracts/IBookmarkDataSerializer.cs @@ -1,6 +1,6 @@ namespace Elsa.Contracts; -public interface IPayloadSerializer +public interface IBookmarkDataSerializer { T Deserialize(string json) where T : notnull; string Serialize(T payload) where T : notnull; diff --git a/src/core/Elsa.Core/Contracts/IEventGenerator.cs b/src/core/Elsa.Core/Contracts/IEventGenerator.cs new file mode 100644 index 000000000..3f928b343 --- /dev/null +++ b/src/core/Elsa.Core/Contracts/IEventGenerator.cs @@ -0,0 +1,12 @@ +namespace Elsa.Contracts; + +/// +/// Implemented by trigger activities that generate events. For example, a timer activity is an event generator. +/// +/// +/// When an event generator activity is marked as startable, it generates new workflow instances. Otherwise, it schedules new workflow executions for the current workflow instance, regardless of whether or not the activity is currently blocking. +/// For example, a timer activity will continuously generate events, causing the workflow instance to execute the timer event and subsequent activities, even if the timer activity wasn't scheduled with the workflow execution stack. +/// +public interface IEventGenerator : ITrigger +{ +} \ No newline at end of file diff --git a/src/core/Elsa.Core/Contracts/INode.cs b/src/core/Elsa.Core/Contracts/INode.cs deleted file mode 100644 index b4ee1fc25..000000000 --- a/src/core/Elsa.Core/Contracts/INode.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Elsa.Contracts; - -public interface INode -{ - string Id { get; set; } - string NodeType { get; set; } - IDictionary Metadata { get; set; } -} \ No newline at end of file diff --git a/src/core/Elsa.Core/Contracts/ITrigger.cs b/src/core/Elsa.Core/Contracts/ITrigger.cs index 493b0d5ac..00395b545 100644 --- a/src/core/Elsa.Core/Contracts/ITrigger.cs +++ b/src/core/Elsa.Core/Contracts/ITrigger.cs @@ -3,21 +3,12 @@ using Elsa.Models; namespace Elsa.Contracts; /// -/// Activities that act as a trigger should implement this interface. +/// Implement this method if your activity needs to provide bookmark data that will be used when it is marked as a trigger. /// -public interface ITrigger : INode +public interface ITrigger : IActivity { /// - /// A value indicating whether this trigger can create a new workflow instances when triggered, or execute the workflow instance this trigger belongs to. + /// Implementors should return a list of objects where each object represents a bookmark datum. For each datum, a trigger is created. /// - TriggerMode TriggerMode { get; set; } - - /// - /// Implementing triggers should return zero or more objects that represent a lookup value. - /// - /// - /// For example, if your trigger can be configured with a signal name to listen for, you would return an object with said signal name as a field. - /// Your auxiliary services would then use this signal name to create a hash and use it to lookup a trigger stored in the database by this hash. - /// - ValueTask> GetTriggerPayloadsAsync(TriggerIndexingContext context, CancellationToken cancellationToken = default); + ValueTask> GetTriggerDataAsync(TriggerIndexingContext context); } \ No newline at end of file diff --git a/src/core/Elsa.Core/Extensions/NodeExtensions.cs b/src/core/Elsa.Core/Extensions/NodeExtensions.cs index 21b8d1c0c..523d555fc 100644 --- a/src/core/Elsa.Core/Extensions/NodeExtensions.cs +++ b/src/core/Elsa.Core/Extensions/NodeExtensions.cs @@ -1,24 +1,9 @@ -using Elsa.Contracts; using Elsa.Models; namespace Elsa.Extensions; public static class NodeExtensions { - public static IEnumerable GetInputs(this INode node) - { - var inputProps = node.GetType().GetProperties().Where(x => typeof(Input).IsAssignableFrom(x.PropertyType)).ToList(); - - var query = - from inputProp in inputProps - select (Input?)inputProp.GetValue(node) - into input - where input != null - select input; - - return query.Select(x => x!).ToList(); - } - public static IEnumerable Flatten(this ActivityNode root) { yield return root; diff --git a/src/core/Elsa.Core/Models/Activity.cs b/src/core/Elsa.Core/Models/Activity.cs index ed3f4ba29..729f2ca3f 100644 --- a/src/core/Elsa.Core/Models/Activity.cs +++ b/src/core/Elsa.Core/Models/Activity.cs @@ -5,11 +5,12 @@ namespace Elsa.Models; public abstract class Activity : IActivity { - protected Activity() => NodeType = TypeNameHelper.GenerateTypeName(GetType()); - protected Activity(string activityType) => NodeType = activityType; + protected Activity() => TypeName = TypeNameHelper.GenerateTypeName(GetType()); + protected Activity(string activityType) => TypeName = activityType; public string Id { get; set; } = default!; - public string NodeType { get; set; } + public string TypeName { get; set; } + public bool CanStartWorkflow { get; set; } public IDictionary Metadata { get; set; } = new Dictionary(); protected virtual ValueTask ExecuteAsync(ActivityExecutionContext context) @@ -18,6 +19,11 @@ public abstract class Activity : IActivity return ValueTask.CompletedTask; } + public ValueTask> GetBookmarkPayloadsAsync(TriggerIndexingContext context, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + protected virtual void Execute(ActivityExecutionContext context) { } diff --git a/src/core/Elsa.Core/Models/ActivityExecutionContext.cs b/src/core/Elsa.Core/Models/ActivityExecutionContext.cs index 280f25e90..069fe9c81 100644 --- a/src/core/Elsa.Core/Models/ActivityExecutionContext.cs +++ b/src/core/Elsa.Core/Models/ActivityExecutionContext.cs @@ -47,29 +47,28 @@ public class ActivityExecutionContext ScheduleActivity(activity, completionCallback); } - public void SetBookmarks(IEnumerable payloads, ExecuteActivityDelegate? callback = default) + public void SetBookmarks(IEnumerable bookmarkData, ExecuteActivityDelegate? callback = default) { - foreach (var hashInput in payloads) - SetBookmark(payloads, callback); + foreach (var bookmarkDatum in bookmarkData) + CreateBookmark(bookmarkDatum, callback); } public void SetBookmarks(IEnumerable bookmarks) => _bookmarks.AddRange(bookmarks); - public void SetBookmark(Bookmark bookmark) => _bookmarks.Add(bookmark); + public void CreateBookmark(Bookmark bookmark) => _bookmarks.Add(bookmark); - public void SetBookmark(object? payload, ExecuteActivityDelegate? callback = default) + public void CreateBookmark(object? bookmarkDatum, ExecuteActivityDelegate? callback = default) { var hasher = GetRequiredService(); - var identityGenerator = GetRequiredService(); - var payloadSerializer = GetRequiredService(); - var payloadJson = payload != null ? payloadSerializer.Serialize(payload) : default; - var hash = payloadJson != null ? hasher.Hash(payloadJson) : default; + var bookmarkDataSerializer = GetRequiredService(); + var bookmarkDatumJson = bookmarkDatum != null ? bookmarkDataSerializer.Serialize(bookmarkDatum) : default; + var hash = bookmarkDatumJson != null ? hasher.Hash(bookmarkDatumJson) : default; - SetBookmark(new Bookmark( + CreateBookmark(new Bookmark( identityGenerator.GenerateId(), - Activity.NodeType, + Activity.TypeName, hash, - payloadJson, + bookmarkDatumJson, Activity.Id, Id, callback?.Method.Name)); diff --git a/src/core/Elsa.Core/Models/Bookmark.cs b/src/core/Elsa.Core/Models/Bookmark.cs index 0e9a194b7..81e8b881c 100644 --- a/src/core/Elsa.Core/Models/Bookmark.cs +++ b/src/core/Elsa.Core/Models/Bookmark.cs @@ -4,7 +4,7 @@ public record Bookmark( string Id, string Name, string? Hash, - string? Payload, + string? Data, string ActivityId, string ActivityInstanceId, string? CallbackMethodName = default diff --git a/src/core/Elsa.Core/Models/EventGenerator.cs b/src/core/Elsa.Core/Models/EventGenerator.cs new file mode 100644 index 000000000..626362e2a --- /dev/null +++ b/src/core/Elsa.Core/Models/EventGenerator.cs @@ -0,0 +1,14 @@ +using Elsa.Contracts; + +namespace Elsa.Models; + +public abstract class EventGenerator : Trigger, IEventGenerator +{ + protected EventGenerator() + { + } + + protected EventGenerator(string triggerType) : base(triggerType) + { + } +} \ No newline at end of file diff --git a/src/core/Elsa.Core/Models/ExpressionExecutionContext.cs b/src/core/Elsa.Core/Models/ExpressionExecutionContext.cs index ccaf596e5..4483a614e 100644 --- a/src/core/Elsa.Core/Models/ExpressionExecutionContext.cs +++ b/src/core/Elsa.Core/Models/ExpressionExecutionContext.cs @@ -6,15 +6,17 @@ public class ExpressionExecutionContext { private readonly IServiceProvider _serviceProvider; - public ExpressionExecutionContext(IServiceProvider serviceProvider, Register register, ExpressionExecutionContext? parentContext) + public ExpressionExecutionContext(IServiceProvider serviceProvider, Register register, ExpressionExecutionContext? parentContext, CancellationToken cancellationToken) { _serviceProvider = serviceProvider; Register = register; ParentContext = parentContext; + CancellationToken = cancellationToken; } public Register Register { get; } public ExpressionExecutionContext? ParentContext { get; set; } + public CancellationToken CancellationToken { get; } public RegisterLocation GetLocation(RegisterLocationReference locationReference) => GetLocationInternal(locationReference) ?? throw new InvalidOperationException(); public object Get(RegisterLocationReference locationReference) => GetLocation(locationReference).Value!; diff --git a/src/core/Elsa.Core/Models/Trigger.cs b/src/core/Elsa.Core/Models/Trigger.cs index 73f347faa..c5cd3418a 100644 --- a/src/core/Elsa.Core/Models/Trigger.cs +++ b/src/core/Elsa.Core/Models/Trigger.cs @@ -8,29 +8,28 @@ public abstract class Trigger : Activity, ITrigger { } - protected Trigger(string triggerType) : base(triggerType) + protected Trigger(string activityType) : base(activityType) { } - - public TriggerMode TriggerMode { get; set; } = TriggerMode.WorkflowDefinition; - ValueTask> ITrigger.GetTriggerPayloadsAsync(TriggerIndexingContext context, CancellationToken cancellationToken) => GetTriggerPayloadsAsync(context, cancellationToken); + + ValueTask> ITrigger.GetTriggerDataAsync(TriggerIndexingContext context) => GetTriggerDataAsync(context); /// - /// Override this method to return a list of trigger payloads. + /// Override this method to return trigger data. /// - protected virtual ValueTask> GetTriggerPayloadsAsync(TriggerIndexingContext context, CancellationToken cancellationToken = default) + protected virtual ValueTask> GetTriggerDataAsync(TriggerIndexingContext context) { - var hashes = GetTriggerPayloads(context); + var hashes = GetTriggerData(context); return ValueTask.FromResult(hashes); } /// - /// Override this method to return a list of trigger payloads. + /// Override this method to return trigger data. /// - protected virtual IEnumerable GetTriggerPayloads(TriggerIndexingContext context) => new[]{ GetTriggerPayload(context) }; + protected virtual IEnumerable GetTriggerData(TriggerIndexingContext context) => new[]{ GetTriggerDatum(context) }; /// - /// Override this method to return a trigger payload. + /// Override this method to return a trigger datum. /// - protected virtual object GetTriggerPayload(TriggerIndexingContext context) => new(); + protected virtual object GetTriggerDatum(TriggerIndexingContext context) => new(); } \ No newline at end of file diff --git a/src/core/Elsa.Core/Models/TriggerIndexingContext.cs b/src/core/Elsa.Core/Models/TriggerIndexingContext.cs index 858ac855e..da80726fc 100644 --- a/src/core/Elsa.Core/Models/TriggerIndexingContext.cs +++ b/src/core/Elsa.Core/Models/TriggerIndexingContext.cs @@ -7,12 +7,14 @@ public class TriggerIndexingContext public WorkflowIndexingContext WorkflowIndexingContext { get; } public ExpressionExecutionContext ExpressionExecutionContext { get; } public ITrigger Trigger { get; } + public CancellationToken CancellationToken { get; } - public TriggerIndexingContext(WorkflowIndexingContext workflowIndexingContext, ExpressionExecutionContext expressionExecutionContext, ITrigger trigger) + public TriggerIndexingContext(WorkflowIndexingContext workflowIndexingContext, ExpressionExecutionContext expressionExecutionContext, ITrigger trigger, CancellationToken cancellationToken) { WorkflowIndexingContext = workflowIndexingContext; ExpressionExecutionContext = expressionExecutionContext; Trigger = trigger; + CancellationToken = cancellationToken; } public T? Get(Input? input) => ExpressionExecutionContext.Get(input); diff --git a/src/core/Elsa.Core/Models/TriggerMode.cs b/src/core/Elsa.Core/Models/TriggerMode.cs deleted file mode 100644 index c38bfb81e..000000000 --- a/src/core/Elsa.Core/Models/TriggerMode.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Elsa.Models; - -/// -/// A set of trigger modes. -/// -public enum TriggerMode -{ - /// - /// The trigger will create a new workflow instance and execute said instance. - /// - WorkflowDefinition, - - /// - /// The trigger will schedule the trigger for execution within the context of the workflow instance. - /// - WorkflowInstance -} \ No newline at end of file diff --git a/src/core/Elsa.Core/Models/WorkflowIndexingContext.cs b/src/core/Elsa.Core/Models/WorkflowIndexingContext.cs index e7a578c6b..795242695 100644 --- a/src/core/Elsa.Core/Models/WorkflowIndexingContext.cs +++ b/src/core/Elsa.Core/Models/WorkflowIndexingContext.cs @@ -4,13 +4,15 @@ namespace Elsa.Models; public class WorkflowIndexingContext { - public WorkflowIndexingContext(Workflow workflow) + public WorkflowIndexingContext(Workflow workflow, CancellationToken cancellationToken) { Workflow = workflow; + CancellationToken = cancellationToken; } public Workflow Workflow { get; } public IDictionary Registers { get; } = new Dictionary(); + public CancellationToken CancellationToken { get; } public Register GetOrCreateRegister(ITrigger activity) { diff --git a/src/core/Elsa.Core/Pipelines/ActivityExecution/Components/ActivityInvokerMiddleware.cs b/src/core/Elsa.Core/Pipelines/ActivityExecution/Components/ActivityInvokerMiddleware.cs index dcbedd351..b8597f091 100644 --- a/src/core/Elsa.Core/Pipelines/ActivityExecution/Components/ActivityInvokerMiddleware.cs +++ b/src/core/Elsa.Core/Pipelines/ActivityExecution/Components/ActivityInvokerMiddleware.cs @@ -68,7 +68,7 @@ public class ActivityInvokerMiddleware : IActivityExecutionMiddleware { var activity = context.Activity; var workflowExecutionContext = context.WorkflowExecutionContext; - var logEntry = new WorkflowExecutionLogEntry(activity.Id, activity.NodeType, _clock.UtcNow, eventName, message, source, payload); + var logEntry = new WorkflowExecutionLogEntry(activity.Id, activity.TypeName, _clock.UtcNow, eventName, message, source, payload); workflowExecutionContext.ExecutionLog.Add(logEntry); } diff --git a/src/core/Elsa.Core/Services/ActivityInvoker.cs b/src/core/Elsa.Core/Services/ActivityInvoker.cs index b11ff3b7f..c540f8aa5 100644 --- a/src/core/Elsa.Core/Services/ActivityInvoker.cs +++ b/src/core/Elsa.Core/Services/ActivityInvoker.cs @@ -28,7 +28,7 @@ public class ActivityInvoker : IActivityInvoker // Setup an activity execution context. var register = workflowExecutionContext.Workflow.CreateRegister(); - var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, register, parentActivityExecutionContext?.ExpressionExecutionContext); + var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, register, parentActivityExecutionContext?.ExpressionExecutionContext, cancellationToken); var activityExecutionContext = new ActivityExecutionContext(workflowExecutionContext, parentActivityExecutionContext, expressionExecutionContext, activity, cancellationToken); // Declare locations. diff --git a/src/core/Elsa.Core/Services/PayloadSerializer.cs b/src/core/Elsa.Core/Services/BookmarkDataSerializer.cs similarity index 85% rename from src/core/Elsa.Core/Services/PayloadSerializer.cs rename to src/core/Elsa.Core/Services/BookmarkDataSerializer.cs index 9be60c233..402d4507c 100644 --- a/src/core/Elsa.Core/Services/PayloadSerializer.cs +++ b/src/core/Elsa.Core/Services/BookmarkDataSerializer.cs @@ -3,11 +3,11 @@ using Elsa.Contracts; namespace Elsa.Services; -public class PayloadSerializer : IPayloadSerializer +public class BookmarkDataSerializer : IBookmarkDataSerializer { private readonly JsonSerializerOptions _settings; - public PayloadSerializer() + public BookmarkDataSerializer() { _settings = new JsonSerializerOptions { diff --git a/src/core/Elsa.Core/Services/Hasher.cs b/src/core/Elsa.Core/Services/Hasher.cs index 354b1e71f..ee6b5c2ea 100644 --- a/src/core/Elsa.Core/Services/Hasher.cs +++ b/src/core/Elsa.Core/Services/Hasher.cs @@ -6,16 +6,16 @@ namespace Elsa.Services; public class Hasher : IHasher { - private readonly IPayloadSerializer _payloadSerializer; + private readonly IBookmarkDataSerializer _bookmarkDataSerializer; - public Hasher(IPayloadSerializer payloadSerializer) + public Hasher(IBookmarkDataSerializer bookmarkDataSerializer) { - _payloadSerializer = payloadSerializer; + _bookmarkDataSerializer = bookmarkDataSerializer; } public string Hash(object value) { - var json = _payloadSerializer.Serialize(value); + var json = _bookmarkDataSerializer.Serialize(value); return Hash(json); } diff --git a/src/core/Elsa.Core/Services/IdentityGraphService.cs b/src/core/Elsa.Core/Services/IdentityGraphService.cs index bf17735da..7fd133c43 100644 --- a/src/core/Elsa.Core/Services/IdentityGraphService.cs +++ b/src/core/Elsa.Core/Services/IdentityGraphService.cs @@ -71,7 +71,7 @@ public class IdentityGraphService : IIdentityGraphService if (!string.IsNullOrWhiteSpace(activityNode.NodeId)) return activityNode.NodeId; - var type = activityNode.Activity.NodeType; + var type = activityNode.Activity.TypeName; var index = GetNextIndexFor(type, identityCounters); var name = $"{Camelize(type)}{index + 1}"; return name; diff --git a/src/core/Elsa.Core/Services/WorkflowStateSerializer.cs b/src/core/Elsa.Core/Services/WorkflowStateSerializer.cs index 18fbd956a..720cf5eef 100644 --- a/src/core/Elsa.Core/Services/WorkflowStateSerializer.cs +++ b/src/core/Elsa.Core/Services/WorkflowStateSerializer.cs @@ -124,11 +124,12 @@ public class WorkflowStateSerializer : IWorkflowStateSerializer { ActivityExecutionContext CreateActivityExecutionContext(ActivityExecutionContextState activityExecutionContextState) { + var cancellationToken = workflowExecutionContext.CancellationToken; var activity = workflowExecutionContext.FindActivityById(activityExecutionContextState.ScheduledActivityId); var register = new Register(activityExecutionContextState.Register.Locations); - var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, register, default); + var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, register, default, cancellationToken); var properties = activityExecutionContextState.Properties; - var activityExecutionContext = new ActivityExecutionContext(workflowExecutionContext, default, expressionExecutionContext, activity, workflowExecutionContext.CancellationToken) + var activityExecutionContext = new ActivityExecutionContext(workflowExecutionContext, default, expressionExecutionContext, activity, cancellationToken) { Id = activityExecutionContextState.Id, Properties = properties diff --git a/src/core/Elsa.Management/Contracts/ITriggerDescriber.cs b/src/core/Elsa.Management/Contracts/ITriggerDescriber.cs deleted file mode 100644 index ddc958756..000000000 --- a/src/core/Elsa.Management/Contracts/ITriggerDescriber.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Elsa.Management.Models; - -namespace Elsa.Management.Contracts; - -public interface ITriggerDescriber -{ - ValueTask DescribeTriggerAsync(Type triggerType, CancellationToken cancellationToken = default); -} \ No newline at end of file diff --git a/src/core/Elsa.Management/Contracts/ITriggerFactory.cs b/src/core/Elsa.Management/Contracts/ITriggerFactory.cs deleted file mode 100644 index f60b62dd8..000000000 --- a/src/core/Elsa.Management/Contracts/ITriggerFactory.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Elsa.Contracts; -using Elsa.Management.Models; - -namespace Elsa.Management.Contracts; - -public interface ITriggerFactory -{ - ITrigger Create(Type type, TriggerConstructorContext context); -} \ No newline at end of file diff --git a/src/core/Elsa.Management/Contracts/ITriggerProvider.cs b/src/core/Elsa.Management/Contracts/ITriggerProvider.cs deleted file mode 100644 index d3c404cf7..000000000 --- a/src/core/Elsa.Management/Contracts/ITriggerProvider.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Elsa.Management.Models; - -namespace Elsa.Management.Contracts; - -public interface ITriggerProvider -{ - ValueTask> GetDescriptorsAsync(CancellationToken cancellationToken = default); -} \ No newline at end of file diff --git a/src/core/Elsa.Management/Contracts/ITriggerRegistry.cs b/src/core/Elsa.Management/Contracts/ITriggerRegistry.cs deleted file mode 100644 index 4ac3a4b0b..000000000 --- a/src/core/Elsa.Management/Contracts/ITriggerRegistry.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Elsa.Management.Models; - -namespace Elsa.Management.Contracts; - -public interface ITriggerRegistry -{ - void Add(object provider, TriggerDescriptor descriptor); - void AddMany(object provider, IEnumerable descriptors); - void Clear(); - void ClearProvider(object provider); - IEnumerable ListAll(); - IEnumerable ListByProvider(object provider); - TriggerDescriptor? Find(Func predicate); - TriggerDescriptor? Find(string triggerType); -} \ No newline at end of file diff --git a/src/core/Elsa.Management/Contracts/ITriggerRegistryPopulator.cs b/src/core/Elsa.Management/Contracts/ITriggerRegistryPopulator.cs deleted file mode 100644 index 3363a5724..000000000 --- a/src/core/Elsa.Management/Contracts/ITriggerRegistryPopulator.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Elsa.Management.Contracts; - -public interface ITriggerRegistryPopulator -{ - ValueTask PopulateRegistryAsync(CancellationToken cancellationToken); -} \ No newline at end of file diff --git a/src/core/Elsa.Management/Extensions/ServiceCollectionExtensions.cs b/src/core/Elsa.Management/Extensions/ServiceCollectionExtensions.cs index 4efc65383..af50fef0f 100644 --- a/src/core/Elsa.Management/Extensions/ServiceCollectionExtensions.cs +++ b/src/core/Elsa.Management/Extensions/ServiceCollectionExtensions.cs @@ -21,11 +21,6 @@ public static class ServiceCollectionExtensions .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/src/core/Elsa.Management/Models/TriggerDescriptor.cs b/src/core/Elsa.Management/Models/TriggerDescriptor.cs index 7be283e6d..dd2c52ac3 100644 --- a/src/core/Elsa.Management/Models/TriggerDescriptor.cs +++ b/src/core/Elsa.Management/Models/TriggerDescriptor.cs @@ -6,7 +6,7 @@ namespace Elsa.Management.Models; public class TriggerDescriptor : NodeDescriptor { - [JsonIgnore] public Func Constructor { get; init; } = default!; + [JsonIgnore] public Func Constructor { get; init; } = default!; } public record TriggerConstructorContext(JsonElement Element, JsonSerializerOptions SerializerOptions); \ No newline at end of file diff --git a/src/core/Elsa.Management/Providers/TypedTriggerProvider.cs b/src/core/Elsa.Management/Providers/TypedTriggerProvider.cs deleted file mode 100644 index 7c9846fc4..000000000 --- a/src/core/Elsa.Management/Providers/TypedTriggerProvider.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Runtime.CompilerServices; -using Elsa.Management.Contracts; -using Elsa.Management.Models; -using Elsa.Management.Options; -using Microsoft.Extensions.Options; - -namespace Elsa.Management.Providers; - -public class TypedTriggerProvider : ITriggerProvider -{ - private readonly ITriggerDescriber _triggerDescriber; - private readonly ApiOptions _options; - - public TypedTriggerProvider(IOptions options, ITriggerDescriber triggerDescriber) - { - _triggerDescriber = triggerDescriber; - _options = options.Value; - } - - public async ValueTask> GetDescriptorsAsync(CancellationToken cancellationToken = default) - { - var triggerTypes = _options.TriggerTypes; - var descriptors = await DescribeTriggerTypesAsync(triggerTypes, cancellationToken).ToListAsync(cancellationToken); - return descriptors; - } - - public async IAsyncEnumerable DescribeTriggerTypesAsync(IEnumerable triggerTypes, [EnumeratorCancellation] CancellationToken cancellationToken) - { - foreach (var triggerType in triggerTypes) - { - var descriptor = await _triggerDescriber.DescribeTriggerAsync(triggerType, cancellationToken); - yield return descriptor; - } - } -} \ No newline at end of file diff --git a/src/core/Elsa.Management/Serialization/Converters/FlowchartJsonConverter.cs b/src/core/Elsa.Management/Serialization/Converters/FlowchartJsonConverter.cs index 5651e5454..aeb14b3c7 100644 --- a/src/core/Elsa.Management/Serialization/Converters/FlowchartJsonConverter.cs +++ b/src/core/Elsa.Management/Serialization/Converters/FlowchartJsonConverter.cs @@ -54,7 +54,7 @@ public class FlowchartJsonConverter : JsonConverter var model = new { - NodeType = value.NodeType, + NodeType = value.TypeName, Id = value.Id, Metadata = value.Metadata, Start = value.Start?.Id, diff --git a/src/core/Elsa.Management/Serialization/Converters/TriggerJsonConverter.cs b/src/core/Elsa.Management/Serialization/Converters/TriggerJsonConverter.cs deleted file mode 100644 index 02fc58cd5..000000000 --- a/src/core/Elsa.Management/Serialization/Converters/TriggerJsonConverter.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization; -using Elsa.Contracts; -using Elsa.Management.Contracts; -using Elsa.Management.Models; - -namespace Elsa.Management.Serialization.Converters; - -/// -/// (De)serializes objects of type . -/// -public class TriggerJsonConverter : JsonConverter -{ - private readonly ITriggerRegistry _triggerRegistry; - private readonly IServiceProvider _serviceProvider; - - public TriggerJsonConverter(ITriggerRegistry triggerRegistry, IServiceProvider serviceProvider) - { - _triggerRegistry = triggerRegistry; - _serviceProvider = serviceProvider; - } - - public override ITrigger Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (!JsonDocument.TryParseValue(ref reader, out var doc)) - throw new JsonException("Failed to parse JsonDocument"); - - if (!doc.RootElement.TryGetProperty("nodeType", out var triggerTypeNameElement)) - throw new JsonException("Failed to extract trigger type property"); - - var triggerType = triggerTypeNameElement.GetString()!; - var triggerDescriptor = _triggerRegistry.Find(triggerType); - - if (triggerDescriptor == null) - throw new Exception($"Trigger of type {triggerType} not found in registry"); - - var newOptions = new JsonSerializerOptions(options); - newOptions.Converters.Add(new InputJsonConverterFactory(_serviceProvider)); - - var context = new TriggerConstructorContext(doc.RootElement, newOptions); - var activity = triggerDescriptor.Constructor(context); - - return activity; - } - - public override void Write(Utf8JsonWriter writer, ITrigger value, JsonSerializerOptions options) - { - var newOptions = new JsonSerializerOptions(options); - newOptions.Converters.Add(new InputJsonConverterFactory(_serviceProvider)); - JsonSerializer.Serialize(writer, value, value.GetType(), newOptions); - } -} \ No newline at end of file diff --git a/src/core/Elsa.Management/Serialization/Converters/TriggerJsonConverterFactory.cs b/src/core/Elsa.Management/Serialization/Converters/TriggerJsonConverterFactory.cs deleted file mode 100644 index 26f0e396a..000000000 --- a/src/core/Elsa.Management/Serialization/Converters/TriggerJsonConverterFactory.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization; -using Elsa.Contracts; -using Elsa.Management.Contracts; - -namespace Elsa.Management.Serialization.Converters; - -public class TriggerJsonConverterFactory : JsonConverterFactory -{ - private readonly ITriggerRegistry _triggerRegistry; - private readonly IServiceProvider _serviceProvider; - - public TriggerJsonConverterFactory(ITriggerRegistry triggerRegistry, IServiceProvider serviceProvider) - { - _triggerRegistry = triggerRegistry; - _serviceProvider = serviceProvider; - } - - // Notice that this factory only creates converters when the type to convert is ITrigger. - // The TriggerJsonConverter will create concrete trigger objects, which then uses regular serialization - public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(ITrigger); - - public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) => new TriggerJsonConverter(_triggerRegistry, _serviceProvider); -} \ No newline at end of file diff --git a/src/core/Elsa.Management/Serialization/WorkflowSerializerOptionsProvider.cs b/src/core/Elsa.Management/Serialization/WorkflowSerializerOptionsProvider.cs index b75ef4d78..67e6dc795 100644 --- a/src/core/Elsa.Management/Serialization/WorkflowSerializerOptionsProvider.cs +++ b/src/core/Elsa.Management/Serialization/WorkflowSerializerOptionsProvider.cs @@ -24,7 +24,6 @@ public class WorkflowSerializerOptionsProvider Create(), Create(), Create(), - Create(), Create(), Create() } diff --git a/src/core/Elsa.Management/Services/ActivityDescriber.cs b/src/core/Elsa.Management/Services/ActivityDescriber.cs index c77a54466..84056ed89 100644 --- a/src/core/Elsa.Management/Services/ActivityDescriber.cs +++ b/src/core/Elsa.Management/Services/ActivityDescriber.cs @@ -51,7 +51,7 @@ public class ActivityDescriber : IActivityDescriber var properties = activityType.GetProperties(); var inputProperties = properties.Where(x => typeof(Input).IsAssignableFrom(x.PropertyType) || x.GetCustomAttribute() != null).ToList(); var outputProperties = properties.Where(x => typeof(Output).IsAssignableFrom(x.PropertyType)).ToList(); - var isTrigger = activityType.IsAssignableTo(typeof(ITrigger)); + var isTrigger = activityType.IsAssignableTo(typeof(IEventGenerator)); var descriptor = new ActivityDescriptor { @@ -66,7 +66,7 @@ public class ActivityDescriber : IActivityDescriber Constructor = context => { var activity = _activityFactory.Create(activityType, context); - activity.NodeType = fullTypeName; + activity.TypeName = fullTypeName; return activity; } }; diff --git a/src/core/Elsa.Management/Services/TriggerDescriber.cs b/src/core/Elsa.Management/Services/TriggerDescriber.cs deleted file mode 100644 index 6fbbe2835..000000000 --- a/src/core/Elsa.Management/Services/TriggerDescriber.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System.ComponentModel; -using System.Reflection; -using Elsa.Attributes; -using Elsa.Helpers; -using Elsa.Management.Contracts; -using Elsa.Management.Models; -using Elsa.Models; -using Humanizer; - -namespace Elsa.Management.Services; - -public class TriggerDescriber : ITriggerDescriber -{ - private readonly IPropertyOptionsResolver _optionsResolver; - private readonly IPropertyDefaultValueResolver _defaultValueResolver; - private readonly ITriggerFactory _activityFactory; - - public TriggerDescriber(IPropertyOptionsResolver optionsResolver, IPropertyDefaultValueResolver defaultValueResolver, ITriggerFactory activityFactory) - { - _optionsResolver = optionsResolver; - _defaultValueResolver = defaultValueResolver; - _activityFactory = activityFactory; - } - - public ValueTask DescribeTriggerAsync(Type triggerType, CancellationToken cancellationToken = default) - { - var ns = TypeNameHelper.GenerateNamespace(triggerType); - var typeName = triggerType.Name; - var fullTypeName = TypeNameHelper.GenerateTypeName(triggerType, ns); - var displayNameAttr = triggerType.GetCustomAttribute(); - var displayName = displayNameAttr?.DisplayName ?? typeName.Humanize(LetterCasing.Title); - var categoryAttr = triggerType.GetCustomAttribute(); - var category = categoryAttr?.Category ?? TypeNameHelper.GetCategoryFromNamespace(ns) ?? "Miscellaneous"; - var descriptionAttr = triggerType.GetCustomAttribute(); - var description = descriptionAttr?.Description; - var properties = triggerType.GetProperties(); - var inputProperties = properties.Where(x => typeof(Input).IsAssignableFrom(x.PropertyType)).ToList(); - - var descriptor = new TriggerDescriptor - { - Category = category, - Description = description, - NodeType = fullTypeName, - DisplayName = displayName, - InputProperties = DescribeInputProperties(inputProperties).ToList(), - Constructor = context => - { - var trigger = _activityFactory.Create(triggerType, context); - trigger.NodeType = fullTypeName; - return trigger; - } - }; - - return ValueTask.FromResult(descriptor); - } - - private IEnumerable DescribeInputProperties(IEnumerable properties) - { - foreach (var propertyInfo in properties) - { - var inputAttribute = propertyInfo.GetCustomAttribute(); - var descriptionAttribute = propertyInfo.GetCustomAttribute(); - var wrappedPropertyType = propertyInfo.PropertyType.GenericTypeArguments[0]; - - yield return new InputDescriptor - ( - inputAttribute?.Name ?? propertyInfo.Name, - wrappedPropertyType, - InputUIHints.GetUIHint(wrappedPropertyType, inputAttribute), - inputAttribute?.DisplayName ?? propertyInfo.Name.Humanize(LetterCasing.Title), - descriptionAttribute?.Description, - _optionsResolver.GetOptions(propertyInfo), - inputAttribute?.Category, - inputAttribute?.Order ?? 0, - _defaultValueResolver.GetDefaultValue(propertyInfo), - inputAttribute?.DefaultSyntax, - //inputAttribute?.SupportedSyntaxes, TODO: Come up with a different way to specify support languages for activity inputs. By default, maybe all pros should support all registered scripting languages? - inputAttribute?.IsReadOnly ?? false, - inputAttribute?.IsBrowsable ?? true - ); - } - } -} \ No newline at end of file diff --git a/src/core/Elsa.Management/Services/TriggerFactory.cs b/src/core/Elsa.Management/Services/TriggerFactory.cs deleted file mode 100644 index d300c87cf..000000000 --- a/src/core/Elsa.Management/Services/TriggerFactory.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Text.Json; -using Elsa.Contracts; -using Elsa.Management.Contracts; -using Elsa.Management.Models; - -namespace Elsa.Management.Services; - -public class TriggerFactory : ITriggerFactory -{ - public ITrigger Create(Type type, TriggerConstructorContext context) - { - var trigger = (ITrigger)context.Element.Deserialize(type, context.SerializerOptions)!; - return trigger; - } -} \ No newline at end of file diff --git a/src/core/Elsa.Management/Services/TriggerRegistry.cs b/src/core/Elsa.Management/Services/TriggerRegistry.cs deleted file mode 100644 index b8c5d96ee..000000000 --- a/src/core/Elsa.Management/Services/TriggerRegistry.cs +++ /dev/null @@ -1,58 +0,0 @@ -using Elsa.Management.Contracts; -using Elsa.Management.Models; - -namespace Elsa.Management.Services; - -public class TriggerRegistry : ITriggerRegistry -{ - private readonly IDictionary> _providedTriggerDescriptors = new Dictionary>(); - private readonly IDictionary _triggerDescriptors = new Dictionary(); - - public void Add(object provider, TriggerDescriptor descriptor) => Add(descriptor, GetOrCreateDescriptors(provider)); - - public void AddMany(object provider, IEnumerable descriptors) - { - var target = GetOrCreateDescriptors(provider); - - foreach (var descriptor in descriptors) - Add(descriptor, target); - } - - public void Clear() - { - _triggerDescriptors.Clear(); - _providedTriggerDescriptors.Clear(); - } - - public void ClearProvider(object provider) - { - var descriptors = ListByProvider(provider).ToList(); - - foreach (var descriptor in descriptors) - _triggerDescriptors.Remove(descriptor.NodeType); - - _providedTriggerDescriptors.Remove(provider); - } - - public IEnumerable ListAll() => _triggerDescriptors.Values; - public IEnumerable ListByProvider(object provider) => _providedTriggerDescriptors.TryGetValue(provider, out var descriptors) ? descriptors : ArraySegment.Empty; - public TriggerDescriptor? Find(Func predicate) => _triggerDescriptors.Values.FirstOrDefault(predicate); - public TriggerDescriptor? Find(string triggerType) => _triggerDescriptors.TryGetValue(triggerType, out var descriptor) ? descriptor : null; - - private void Add(TriggerDescriptor descriptor, ICollection target) - { - _triggerDescriptors.Add(descriptor.NodeType, descriptor); - target.Add(descriptor); - } - - private ICollection GetOrCreateDescriptors(object provider) - { - if (_providedTriggerDescriptors.TryGetValue(provider, out var descriptors)) - return descriptors; - - descriptors = new List(); - _providedTriggerDescriptors.Add(provider, descriptors); - - return descriptors; - } -} \ No newline at end of file diff --git a/src/core/Elsa.Management/Services/TriggerRegistryPopulator.cs b/src/core/Elsa.Management/Services/TriggerRegistryPopulator.cs deleted file mode 100644 index 776e95c7a..000000000 --- a/src/core/Elsa.Management/Services/TriggerRegistryPopulator.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Elsa.Management.Contracts; - -namespace Elsa.Management.Services; - -/// -/// Populates the with descriptors provided by s. -/// -public class TriggerRegistryPopulator : ITriggerRegistryPopulator -{ - private readonly IEnumerable _providers; - private readonly ITriggerRegistry _registry; - - public TriggerRegistryPopulator(IEnumerable providers, ITriggerRegistry registry) - { - _providers = providers; - _registry = registry; - } - - public async ValueTask PopulateRegistryAsync(CancellationToken cancellationToken) - { - foreach (var provider in _providers) - { - var descriptors = await provider.GetDescriptorsAsync(cancellationToken); - _registry.AddMany(provider, descriptors); - } - } -} \ No newline at end of file diff --git a/src/core/Elsa/Extensions/ServiceCollectionExtensions.cs b/src/core/Elsa/Extensions/ServiceCollectionExtensions.cs index 28d7105b9..a463a6d25 100644 --- a/src/core/Elsa/Extensions/ServiceCollectionExtensions.cs +++ b/src/core/Elsa/Extensions/ServiceCollectionExtensions.cs @@ -44,7 +44,7 @@ public static class ServiceCollectionExtensions .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton() + .AddSingleton() // DSL. .AddDsl() @@ -75,5 +75,4 @@ public static class ServiceCollectionExtensions public static IServiceCollection AddWorkflowProvider(this IServiceCollection services) where T : class, IWorkflowProvider => services.AddSingleton(); public static IServiceCollection AddStimulusHandler(this IServiceCollection services) where T : class, IStimulusHandler => services.AddSingleton(); public static IServiceCollection AddInstructionInterpreter(this IServiceCollection services) where T : class, IWorkflowInstructionInterpreter => services.AddSingleton(); - public static IServiceCollection ConfigureWorkflowRuntime(this IServiceCollection services, Action configure) => services.Configure(configure); } \ No newline at end of file diff --git a/src/dsl/Elsa.Dsl/AssemblyInfo.cs b/src/dsl/Elsa.Dsl/AssemblyInfo.cs index e46bb2692..e05431af1 100644 --- a/src/dsl/Elsa.Dsl/AssemblyInfo.cs +++ b/src/dsl/Elsa.Dsl/AssemblyInfo.cs @@ -1,2 +1,2 @@ using System; -[assembly: CLSCompliant(true)] \ No newline at end of file +[assembly: CLSCompliant(false)] \ No newline at end of file diff --git a/src/dsl/Elsa.Dsl/Extensions/TypeSystemExtensions.cs b/src/dsl/Elsa.Dsl/Extensions/TypeSystemExtensions.cs index b138b9730..8a6bb8ac9 100644 --- a/src/dsl/Elsa.Dsl/Extensions/TypeSystemExtensions.cs +++ b/src/dsl/Elsa.Dsl/Extensions/TypeSystemExtensions.cs @@ -21,7 +21,7 @@ public static class TypeSystemExtensions { var kind = TypeKind.Unknown; var isActivity = typeof(IActivity).IsAssignableFrom(type); - var isTrigger = typeof(ITrigger).IsAssignableFrom(type); + var isTrigger = typeof(IEventGenerator).IsAssignableFrom(type); var isPrimitive = type.IsPrimitive; var isObject = type.IsClass || type.IsValueType; diff --git a/src/modules/Elsa.Modules.AzureServiceBus/Activities/MessageReceived.cs b/src/modules/Elsa.Modules.AzureServiceBus/Activities/MessageReceived.cs index bbd2da279..9ba5e6e2c 100644 --- a/src/modules/Elsa.Modules.AzureServiceBus/Activities/MessageReceived.cs +++ b/src/modules/Elsa.Modules.AzureServiceBus/Activities/MessageReceived.cs @@ -1,4 +1,3 @@ -using Azure.Messaging.ServiceBus; using Elsa.Attributes; using Elsa.Formatting.Contracts; using Elsa.Models; @@ -33,12 +32,12 @@ public class MessageReceived : Trigger /// public IFormatter? Formatter { get; set; } - protected override object GetTriggerPayload(TriggerIndexingContext context) => GetPayload(context.ExpressionExecutionContext); + protected override object GetTriggerDatum(TriggerIndexingContext context) => GetBookmarkData(context.ExpressionExecutionContext); protected override void Execute(ActivityExecutionContext context) { - var payload = GetPayload(context.ExpressionExecutionContext); - context.SetBookmark(payload, Resume); + var bookmarkData = GetBookmarkData(context.ExpressionExecutionContext); + context.CreateBookmark(bookmarkData, Resume); } private async ValueTask Resume(ActivityExecutionContext context) @@ -52,7 +51,7 @@ public class MessageReceived : Trigger context.Set(ReceivedMessageBody, body); } - private object GetPayload(ExpressionExecutionContext context) + private object GetBookmarkData(ExpressionExecutionContext context) { var queueOrTopic = context.Get(QueueOrTopic)!; var subscription = context.Get(Subscription); diff --git a/src/modules/Elsa.Modules.AzureServiceBus/Handlers/UpdateWorkers.cs b/src/modules/Elsa.Modules.AzureServiceBus/Handlers/UpdateWorkers.cs index f74e26938..f68f30c1a 100644 --- a/src/modules/Elsa.Modules.AzureServiceBus/Handlers/UpdateWorkers.cs +++ b/src/modules/Elsa.Modules.AzureServiceBus/Handlers/UpdateWorkers.cs @@ -14,10 +14,10 @@ namespace Elsa.Modules.AzureServiceBus.Handlers; /// public class UpdateWorkers : INotificationHandler, INotificationHandler, INotificationHandler { - private readonly IPayloadSerializer _serializer; + private readonly IBookmarkDataSerializer _serializer; private readonly IWorkerManager _workerManager; - public UpdateWorkers(IPayloadSerializer serializer, IWorkerManager workerManager) + public UpdateWorkers(IBookmarkDataSerializer serializer, IWorkerManager workerManager) { _serializer = serializer; _workerManager = workerManager; @@ -28,8 +28,8 @@ public class UpdateWorkers : INotificationHandler, INot /// public async Task HandleAsync(WorkflowTriggersIndexed notification, CancellationToken cancellationToken) { - var added = notification.IndexedWorkflowTriggers.AddedTriggers.Filter().Select(x => DeserializePayload(x.Payload!)); - var removed = notification.IndexedWorkflowTriggers.RemovedTriggers.Filter().Select(x => DeserializePayload(x.Payload!)); + var added = notification.IndexedWorkflowTriggers.AddedTriggers.Filter().Select(x => DeserializePayload(x.Data!)); + var removed = notification.IndexedWorkflowTriggers.RemovedTriggers.Filter().Select(x => DeserializePayload(x.Data!)); await StopWorkersAsync(removed, cancellationToken); await StartWorkersAsync(added, cancellationToken); @@ -40,7 +40,7 @@ public class UpdateWorkers : INotificationHandler, INot /// public async Task HandleAsync(WorkflowBookmarksDeleted notification, CancellationToken cancellationToken) { - var payloads = notification.Bookmarks.Filter().Select(x => DeserializePayload(x.Payload!)); + var payloads = notification.Bookmarks.Filter().Select(x => DeserializePayload(x.Data!)); await StopWorkersAsync(payloads, cancellationToken); } @@ -49,7 +49,7 @@ public class UpdateWorkers : INotificationHandler, INot /// public async Task HandleAsync(WorkflowBookmarksSaved notification, CancellationToken cancellationToken) { - var payloads = notification.Bookmarks.Filter().Select(x => DeserializePayload(x.Payload!)); + var payloads = notification.Bookmarks.Filter().Select(x => DeserializePayload(x.Data!)); await StartWorkersAsync(payloads, cancellationToken); } diff --git a/src/modules/Elsa.Modules.Http/Activities/HttpTrigger.cs b/src/modules/Elsa.Modules.Http/Activities/HttpEndpoint.cs similarity index 58% rename from src/modules/Elsa.Modules.Http/Activities/HttpTrigger.cs rename to src/modules/Elsa.Modules.Http/Activities/HttpEndpoint.cs index 211ed7bec..0f61067e6 100644 --- a/src/modules/Elsa.Modules.Http/Activities/HttpTrigger.cs +++ b/src/modules/Elsa.Modules.Http/Activities/HttpEndpoint.cs @@ -8,7 +8,7 @@ using Elsa.Modules.Http.Models; namespace Elsa.Modules.Http; -public class HttpTrigger : Trigger +public class HttpEndpoint : Trigger { [Input] public Input Path { get; set; } = default!; @@ -20,14 +20,14 @@ public class HttpTrigger : Trigger [Output] public Output? Result { get; set; } - protected override IEnumerable GetTriggerPayloads(TriggerIndexingContext context) => GetHashInputs(context.ExpressionExecutionContext); - protected override void Execute(ActivityExecutionContext context) => context.SetBookmarks(GetHashInputs(context.ExpressionExecutionContext)); + protected override IEnumerable GetTriggerData(TriggerIndexingContext context) => GetBookmarkData(context.ExpressionExecutionContext); + protected override void Execute(ActivityExecutionContext context) => context.SetBookmarks(GetBookmarkData(context.ExpressionExecutionContext)); - private IEnumerable GetHashInputs(ExpressionExecutionContext context) + private IEnumerable GetBookmarkData(ExpressionExecutionContext context) { - // Generate a bookmark hash for path and selected methods. + // Generate bookmark data for path and selected methods. var path = context.Get(Path); var methods = context.Get(SupportedMethods); - return methods!.Select(x => new HttpTriggerPayload(path!, x.ToLowerInvariant())).Cast().ToArray(); + return methods!.Select(x => new HttpBookmarkData(path!, x.ToLowerInvariant())).Cast().ToArray(); } } \ No newline at end of file diff --git a/src/modules/Elsa.Modules.Http/Middleware/HttpTriggerMiddleware.cs b/src/modules/Elsa.Modules.Http/Middleware/HttpTriggerMiddleware.cs index fbcf15ae0..5b95020ee 100644 --- a/src/modules/Elsa.Modules.Http/Middleware/HttpTriggerMiddleware.cs +++ b/src/modules/Elsa.Modules.Http/Middleware/HttpTriggerMiddleware.cs @@ -26,8 +26,8 @@ public class HttpTriggerMiddleware var path = GetPath(httpContext); var method = httpContext.Request.Method!.ToLowerInvariant(); var abortToken = httpContext.RequestAborted; - var hash = _hasher.Hash(new HttpTriggerPayload(path, method)); - var activityTypeName = TypeNameHelper.GenerateTypeName(); + var hash = _hasher.Hash(new HttpBookmarkData(path, method)); + var activityTypeName = TypeNameHelper.GenerateTypeName(); var stimulus = Stimulus.Standard(activityTypeName, hash); var executionResults = (await workflowServer.ExecuteStimulusAsync(stimulus, abortToken)).ToList(); diff --git a/src/modules/Elsa.Modules.Http/Models/HttpTriggerPayload.cs b/src/modules/Elsa.Modules.Http/Models/HttpBookmarkData.cs similarity index 82% rename from src/modules/Elsa.Modules.Http/Models/HttpTriggerPayload.cs rename to src/modules/Elsa.Modules.Http/Models/HttpBookmarkData.cs index 2d6e2c90a..ab54c5c6a 100644 --- a/src/modules/Elsa.Modules.Http/Models/HttpTriggerPayload.cs +++ b/src/modules/Elsa.Modules.Http/Models/HttpBookmarkData.cs @@ -1,11 +1,11 @@ namespace Elsa.Modules.Http.Models; -public record HttpTriggerPayload +public record HttpBookmarkData { private readonly string _path = default!; private readonly string _method = default!; - public HttpTriggerPayload(string path, string method) + public HttpBookmarkData(string path, string method) { Path = path; Method = method; diff --git a/src/modules/Elsa.Modules.Scheduling/Activities/Delay.cs b/src/modules/Elsa.Modules.Scheduling/Activities/Delay.cs index e7102fb77..a52f257c7 100644 --- a/src/modules/Elsa.Modules.Scheduling/Activities/Delay.cs +++ b/src/modules/Elsa.Modules.Scheduling/Activities/Delay.cs @@ -16,7 +16,7 @@ public class Delay : Activity var resumeAt = clock.UtcNow.Add(timeSpan); var payload = new DelayPayload(resumeAt); - context.SetBookmark(payload); + context.CreateBookmark(payload); } } diff --git a/src/modules/Elsa.Modules.Scheduling/Services/WorkflowBookmarkScheduler.cs b/src/modules/Elsa.Modules.Scheduling/Services/WorkflowBookmarkScheduler.cs index 906b56652..f8bcf5bd8 100644 --- a/src/modules/Elsa.Modules.Scheduling/Services/WorkflowBookmarkScheduler.cs +++ b/src/modules/Elsa.Modules.Scheduling/Services/WorkflowBookmarkScheduler.cs @@ -35,7 +35,7 @@ public class WorkflowBookmarkScheduler : IWorkflowBookmarkScheduler // Schedule a trigger for each bookmark. foreach (var bookmark in delayBookmarks) { - var payload = JsonSerializer.Deserialize(bookmark.Payload!)!; + var payload = JsonSerializer.Deserialize(bookmark.Data!)!; var resumeAt = payload.ResumeAt; var job = new ResumeWorkflowJob(workflowInstanceId, bookmark.ToBookmark()); var schedule = new SpecificInstantSchedule(resumeAt); diff --git a/src/modules/Elsa.Modules.Scheduling/Services/WorkflowTriggerScheduler.cs b/src/modules/Elsa.Modules.Scheduling/Services/WorkflowTriggerScheduler.cs index 8c5e0be25..b6817587b 100644 --- a/src/modules/Elsa.Modules.Scheduling/Services/WorkflowTriggerScheduler.cs +++ b/src/modules/Elsa.Modules.Scheduling/Services/WorkflowTriggerScheduler.cs @@ -34,7 +34,7 @@ public class WorkflowTriggerScheduler : IWorkflowTriggerScheduler foreach (var trigger in timerTriggers) { // Schedule trigger. - var (dateTime, timeSpan) = JsonSerializer.Deserialize(trigger.Payload!)!; + var (dateTime, timeSpan) = JsonSerializer.Deserialize(trigger.Data!)!; var groupKeys = new[] { RootGroupKey, trigger.WorkflowDefinitionId }; await _jobScheduler.ScheduleAsync(new RunWorkflowJob(trigger.WorkflowDefinitionId), new RecurringSchedule(dateTime, timeSpan), groupKeys, cancellationToken); } diff --git a/src/modules/Elsa.Modules.Scheduling/Triggers/Timer.cs b/src/modules/Elsa.Modules.Scheduling/Triggers/Timer.cs index 440be5eae..9dc68ecb9 100644 --- a/src/modules/Elsa.Modules.Scheduling/Triggers/Timer.cs +++ b/src/modules/Elsa.Modules.Scheduling/Triggers/Timer.cs @@ -7,13 +7,13 @@ using Elsa.Models; namespace Elsa.Modules.Scheduling.Triggers; /// -/// Represents a timer to periodically trigger the workflow it is associated with. +/// Represents a timer to periodically trigger the workflow. /// -public class Timer : Trigger +public class Timer : EventGenerator { [Input] public Input Interval { get; set; } = default!; - protected override IEnumerable GetTriggerPayloads(TriggerIndexingContext context) + protected override IEnumerable GetTriggerData(TriggerIndexingContext context) { var interval = context.ExpressionExecutionContext.Get(Interval); var clock = context.ExpressionExecutionContext.GetRequiredService(); diff --git a/src/persistence/Elsa.Persistence.Abstractions/Entities/WorkflowBookmark.cs b/src/persistence/Elsa.Persistence.Abstractions/Entities/WorkflowBookmark.cs index b9a693f28..c1598dfcb 100644 --- a/src/persistence/Elsa.Persistence.Abstractions/Entities/WorkflowBookmark.cs +++ b/src/persistence/Elsa.Persistence.Abstractions/Entities/WorkflowBookmark.cs @@ -6,7 +6,7 @@ public class WorkflowBookmark : Entity { public string Name { get; init; } = default!; public string? Hash { get; set; } - public string? Payload { get; set; } + public string? Data { get; set; } public string WorkflowDefinitionId { get; init; } = default!; public string WorkflowInstanceId { get; init; } = default!; public string CorrelationId { get; init; } = default!; @@ -14,7 +14,7 @@ public class WorkflowBookmark : Entity public string ActivityInstanceId { get; init; } = default!; public string? CallbackMethodName { get; set; } - public Bookmark ToBookmark() => new(Id, Name, Hash, Payload, ActivityId, ActivityInstanceId, CallbackMethodName); + public Bookmark ToBookmark() => new(Id, Name, Hash, Data, ActivityId, ActivityInstanceId, CallbackMethodName); public static WorkflowBookmark FromBookmark(Bookmark bookmark, WorkflowInstance workflowInstance) => new() @@ -24,7 +24,7 @@ public class WorkflowBookmark : Entity WorkflowInstanceId = workflowInstance.Id, CorrelationId = workflowInstance.CorrelationId, Hash = bookmark.Hash, - Payload = bookmark.Payload, + Data = bookmark.Data, Name = bookmark.Name, ActivityId = bookmark.ActivityId, ActivityInstanceId = bookmark.ActivityInstanceId, diff --git a/src/persistence/Elsa.Persistence.Abstractions/Entities/WorkflowTrigger.cs b/src/persistence/Elsa.Persistence.Abstractions/Entities/WorkflowTrigger.cs index c0a236ce3..a04ce0486 100644 --- a/src/persistence/Elsa.Persistence.Abstractions/Entities/WorkflowTrigger.cs +++ b/src/persistence/Elsa.Persistence.Abstractions/Entities/WorkflowTrigger.cs @@ -8,5 +8,5 @@ public class WorkflowTrigger : Entity public string WorkflowDefinitionId { get; set; } = default!; public string Name { get; set; } = default!; public string? Hash { get; set; } - public string? Payload { get; set; } + public string? Data { get; set; } } \ No newline at end of file diff --git a/src/persistence/Elsa.Persistence.Abstractions/Requests/FindWorkflowTriggersByName.cs b/src/persistence/Elsa.Persistence.Abstractions/Requests/FindWorkflowTriggersByName.cs index bcb806d61..df3196e7a 100644 --- a/src/persistence/Elsa.Persistence.Abstractions/Requests/FindWorkflowTriggersByName.cs +++ b/src/persistence/Elsa.Persistence.Abstractions/Requests/FindWorkflowTriggersByName.cs @@ -7,5 +7,5 @@ namespace Elsa.Persistence.Requests; public record FindWorkflowTriggersByName(string Name, string? Hash = default) : IRequest> { - public static FindWorkflowTriggersByName ForTrigger(string? hash = default) where T : ITrigger => new(TypeNameHelper.GenerateTypeName(), hash); + public static FindWorkflowTriggersByName ForTrigger(string? hash = default) where T : IEventGenerator => new(TypeNameHelper.GenerateTypeName(), hash); } \ No newline at end of file diff --git a/src/runtime/Elsa.Runtime.ProtoActor/Actors/WorkflowOperatorActor.cs b/src/runtime/Elsa.Runtime.ProtoActor/Actors/WorkflowOperatorActor.cs index e76346455..76b6684e4 100644 --- a/src/runtime/Elsa.Runtime.ProtoActor/Actors/WorkflowOperatorActor.cs +++ b/src/runtime/Elsa.Runtime.ProtoActor/Actors/WorkflowOperatorActor.cs @@ -71,7 +71,7 @@ public class WorkflowOperatorActor : IActor { Id = x.Id, Hash = x.Hash, - Payload = x.Payload, + Payload = x.Data, Name = x.Name, ActivityId = x.ActivityId, ActivityInstanceId = x.ActivityInstanceId, diff --git a/src/runtime/Elsa.Runtime.ProtoActor/Services/ProtoActorWorkflowInvoker.cs b/src/runtime/Elsa.Runtime.ProtoActor/Services/ProtoActorWorkflowInvoker.cs index 8e2bb04fe..332f9b67c 100644 --- a/src/runtime/Elsa.Runtime.ProtoActor/Services/ProtoActorWorkflowInvoker.cs +++ b/src/runtime/Elsa.Runtime.ProtoActor/Services/ProtoActorWorkflowInvoker.cs @@ -110,7 +110,7 @@ public class ProtoActorWorkflowInvoker : IWorkflowInvoker Id = bookmark.Id, Name = bookmark.Name, Hash = bookmark.Hash, - Payload = bookmark.Payload, + Payload = bookmark.Data, ActivityId = bookmark.ActivityId, ActivityInstanceId = bookmark.ActivityInstanceId, CallbackMethodName = bookmark.CallbackMethodName, diff --git a/src/runtime/Elsa.Runtime/HostedServices/RegisterDescriptors.cs b/src/runtime/Elsa.Runtime/HostedServices/RegisterDescriptors.cs index da558a48c..69d3ef654 100644 --- a/src/runtime/Elsa.Runtime/HostedServices/RegisterDescriptors.cs +++ b/src/runtime/Elsa.Runtime/HostedServices/RegisterDescriptors.cs @@ -6,21 +6,7 @@ namespace Elsa.Runtime.HostedServices; public class RegisterDescriptors : IHostedService { private readonly IActivityRegistryPopulator _activityRegistryPopulator; - private readonly ITriggerRegistryPopulator _triggerRegistryPopulator; - - public RegisterDescriptors(IActivityRegistryPopulator activityRegistryPopulator, ITriggerRegistryPopulator triggerRegistryPopulator) - { - _activityRegistryPopulator = activityRegistryPopulator; - _triggerRegistryPopulator = triggerRegistryPopulator; - } - - public async Task StartAsync(CancellationToken cancellationToken) - { - var activityRegistryTask = _activityRegistryPopulator.PopulateRegistryAsync(cancellationToken).AsTask(); - var triggerRegistryTask = _triggerRegistryPopulator.PopulateRegistryAsync(cancellationToken).AsTask(); - - await Task.WhenAll(activityRegistryTask, triggerRegistryTask); - } - + public RegisterDescriptors(IActivityRegistryPopulator activityRegistryPopulator) => _activityRegistryPopulator = activityRegistryPopulator; + public async Task StartAsync(CancellationToken cancellationToken) => await _activityRegistryPopulator.PopulateRegistryAsync(cancellationToken).AsTask(); public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; } \ No newline at end of file diff --git a/src/runtime/Elsa.Runtime/Interpreters/ResumeWorkflowInstructionInterpreter.cs b/src/runtime/Elsa.Runtime/Interpreters/ResumeWorkflowInstructionInterpreter.cs index a06f273a3..6af02a508 100644 --- a/src/runtime/Elsa.Runtime/Interpreters/ResumeWorkflowInstructionInterpreter.cs +++ b/src/runtime/Elsa.Runtime/Interpreters/ResumeWorkflowInstructionInterpreter.cs @@ -50,7 +50,7 @@ public class ResumeWorkflowInstructionInterpreter : WorkflowInstructionInterpret } // Resume workflow instance. - var bookmark = new Bookmark(workflowBookmark.Id, workflowBookmark.Name, workflowBookmark.Hash, workflowBookmark.Payload, workflowBookmark.ActivityId, workflowBookmark.ActivityInstanceId, workflowBookmark.CallbackMethodName); + var bookmark = new Bookmark(workflowBookmark.Id, workflowBookmark.Name, workflowBookmark.Hash, workflowBookmark.Data, workflowBookmark.ActivityId, workflowBookmark.ActivityInstanceId, workflowBookmark.CallbackMethodName); var workflowState = workflowInstance.WorkflowState; var input = instruction.Input; var workflowExecutionResult = await _workflowRunner.RunAsync(workflow, workflowState, bookmark, input, cancellationToken); diff --git a/src/runtime/Elsa.Runtime/Services/TriggerIndexer.cs b/src/runtime/Elsa.Runtime/Services/TriggerIndexer.cs index d0022d989..9dcef0135 100644 --- a/src/runtime/Elsa.Runtime/Services/TriggerIndexer.cs +++ b/src/runtime/Elsa.Runtime/Services/TriggerIndexer.cs @@ -113,26 +113,79 @@ public class TriggerIndexer : ITriggerIndexer private async IAsyncEnumerable GetTriggersAsync(Workflow workflow, [EnumeratorCancellation] CancellationToken cancellationToken = default) { - var context = new WorkflowIndexingContext(workflow); - var triggerNodes = _activityWalker.Walk(workflow.Root).Flatten().Where(x => x.Activity is ITrigger { TriggerMode: TriggerMode.WorkflowDefinition }).ToList(); + var context = new WorkflowIndexingContext(workflow, cancellationToken); + + // Get a list of activities that are configured as "startable". + var startableNodes = _activityWalker + .Walk(workflow.Root) + .Flatten() + .Where(x => x.Activity.CanStartWorkflow) + .ToList(); - foreach (var triggerNode in triggerNodes) + // For each startable node, create triggers. + foreach (var node in startableNodes) { - var triggers = await GetTriggersAsync(workflow, context, (ITrigger)triggerNode.Activity, cancellationToken); + var triggers = await GetTriggersAsync(context, (IEventGenerator)node.Activity, cancellationToken); foreach (var trigger in triggers) yield return trigger; } } - private async Task> GetTriggersAsync(Workflow workflow, WorkflowIndexingContext context, ITrigger trigger, CancellationToken cancellationToken) + private async Task> GetTriggersAsync(WorkflowIndexingContext context, IActivity activity, CancellationToken cancellationToken) + { + // If the activity implements ITrigger, request its trigger data. Otherwise, create one trigger datum. + if (activity is ITrigger trigger) + return await CreateWorkflowTriggersAsync(context, trigger); + + // Else, create a single workflow trigger with no additional data. + var simpleTrigger = CreateWorkflowTrigger(context, activity); + + return new[] { simpleTrigger }; + } + + private WorkflowTrigger CreateWorkflowTrigger(WorkflowIndexingContext context, IActivity activity) + { + var workflow = context.Workflow; + return new WorkflowTrigger + { + Id = _identityGenerator.GenerateId(), + WorkflowDefinitionId = workflow.Identity.DefinitionId, + Name = activity.TypeName + }; + } + + private async Task> CreateWorkflowTriggersAsync(WorkflowIndexingContext context, ITrigger trigger) + { + var workflow = context.Workflow; + var cancellationToken = context.CancellationToken; + var expressionExecutionContext = await CreateExpressionExecutionContextAsync(context, trigger); + + var triggerIndexingContext = new TriggerIndexingContext(context, expressionExecutionContext, trigger, cancellationToken); + var triggerData = await TryGetTriggerDataAsync(trigger, triggerIndexingContext); + var triggerTypeName = trigger.TypeName; + + var triggers = triggerData.Select(x => new WorkflowTrigger + { + Id = _identityGenerator.GenerateId(), + WorkflowDefinitionId = workflow.Identity.DefinitionId, + Name = triggerTypeName, + Hash = _hasher.Hash(x), + Data = JsonSerializer.Serialize(x) + }); + + return triggers.ToList(); + } + + private async Task CreateExpressionExecutionContextAsync(WorkflowIndexingContext context, ITrigger trigger) { var inputs = trigger.GetInputs(); var assignedInputs = inputs.Where(x => x.LocationReference != null!).ToList(); var register = context.GetOrCreateRegister(trigger); - var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, register, default); + var cancellationToken = context.CancellationToken; + var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, register, default, cancellationToken); - // Evaluate trigger inputs. + // Evaluate activity inputs before requesting trigger data. foreach (var input in assignedInputs) { var locationReference = input.LocationReference; @@ -148,32 +201,18 @@ public class TriggerIndexer : ITriggerIndexer } } - var triggerIndexingContext = new TriggerIndexingContext(context, expressionExecutionContext, trigger); - var payloads = await TryGetPayloadsAsync(trigger, triggerIndexingContext, cancellationToken); - var triggerType = trigger.GetType(); - var triggerTypeName = TypeNameHelper.GenerateTypeName(triggerType); - - var triggers = payloads.Select(x => new WorkflowTrigger - { - Id = _identityGenerator.GenerateId(), - WorkflowDefinitionId = workflow.Identity.DefinitionId, - Name = triggerTypeName, - Hash = _hasher.Hash(x), - Payload = JsonSerializer.Serialize(x) - }); - - return triggers; + return expressionExecutionContext; } - private async Task> TryGetPayloadsAsync(ITrigger trigger, TriggerIndexingContext context, CancellationToken cancellationToken) + private async Task> TryGetTriggerDataAsync(ITrigger trigger, TriggerIndexingContext context) { try { - return (await trigger.GetTriggerPayloadsAsync(context, cancellationToken)).ToList(); + return (await trigger.GetTriggerDataAsync(context)).ToList(); } catch (Exception e) { - _logger.LogWarning(e, "Failed to get hash inputs"); + _logger.LogWarning(e, "Failed to get trigger data for activity {ActivityId}", trigger.Id); } return Array.Empty(); diff --git a/src/samples/aspnet/Elsa.Samples.Web1/Program.cs b/src/samples/aspnet/Elsa.Samples.Web1/Program.cs index d9acb278c..1691bf5bd 100644 --- a/src/samples/aspnet/Elsa.Samples.Web1/Program.cs +++ b/src/samples/aspnet/Elsa.Samples.Web1/Program.cs @@ -66,7 +66,7 @@ services .AddActivity() .AddActivity() .AddActivity() - .AddActivity() + .AddActivity() .AddActivity() .AddActivity() .AddActivity() diff --git a/src/samples/aspnet/Elsa.Samples.Web1/Workflows/ForkedHttpWorkflow.cs b/src/samples/aspnet/Elsa.Samples.Web1/Workflows/ForkedHttpWorkflow.cs index 5cdea29cd..e7aef7b29 100644 --- a/src/samples/aspnet/Elsa.Samples.Web1/Workflows/ForkedHttpWorkflow.cs +++ b/src/samples/aspnet/Elsa.Samples.Web1/Workflows/ForkedHttpWorkflow.cs @@ -20,7 +20,7 @@ public class ForkedHttpWorkflow : IWorkflow { Activities = { - new HttpTrigger + new HttpEndpoint { Path = new Input("/fork"), SupportedMethods = new Input>(new[] { HttpMethods.Get }) @@ -34,7 +34,7 @@ public class ForkedHttpWorkflow : IWorkflow { Activities = { - new HttpTrigger { Path = new Input("/fork/branch-1"), }, + new HttpEndpoint { Path = new Input("/fork/branch-1"), }, new WriteLine("Branch 1 continues!") } }, @@ -42,7 +42,7 @@ public class ForkedHttpWorkflow : IWorkflow { Activities = { - new HttpTrigger { Path = new Input("/fork/branch-2"), }, + new HttpEndpoint { Path = new Input("/fork/branch-2"), }, new WriteLine("Branch 2 continues!") } } diff --git a/src/samples/aspnet/Elsa.Samples.Web1/Workflows/HttpWorkflow.cs b/src/samples/aspnet/Elsa.Samples.Web1/Workflows/HttpWorkflow.cs index c4df9e4c1..b0b98dbcc 100644 --- a/src/samples/aspnet/Elsa.Samples.Web1/Workflows/HttpWorkflow.cs +++ b/src/samples/aspnet/Elsa.Samples.Web1/Workflows/HttpWorkflow.cs @@ -24,7 +24,7 @@ public class HttpWorkflow : IWorkflow { Activities = { - new HttpTrigger + new HttpEndpoint { Path = new Input("/hello-world"), SupportedMethods = new Input>(new[] { HttpMethods.Get }) @@ -34,7 +34,7 @@ public class HttpWorkflow : IWorkflow Condition = new Input(true), Then = new Sequence( new WriteLine("It's true!"), - new HttpTrigger + new HttpEndpoint { Path = new Input("/hello-world/true"), SupportedMethods = new Input>(new[] { HttpMethods.Post }) diff --git a/src/samples/aspnet/Elsa.Samples.Web2/Program.cs b/src/samples/aspnet/Elsa.Samples.Web2/Program.cs index 0f536b602..3da2867ef 100644 --- a/src/samples/aspnet/Elsa.Samples.Web2/Program.cs +++ b/src/samples/aspnet/Elsa.Samples.Web2/Program.cs @@ -3,13 +3,12 @@ using Elsa.Extensions; using Elsa.Modules.Http.Extensions; using Elsa.Persistence.InMemory.Extensions; using Elsa.Pipelines.WorkflowExecution.Components; -using Elsa.Runtime.Middleware; +using Elsa.Runtime.Extensions; using Elsa.Runtime.ProtoActor.Extensions; using Elsa.Samples.Web2.Workflows; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using WorkflowExecutionBuilderExtensions = Elsa.Runtime.Extensions.WorkflowExecutionBuilderExtensions; var builder = WebApplication.CreateBuilder(args); @@ -27,7 +26,7 @@ builder.Services var app = builder.Build(); // Configure workflow engine execution pipeline. -app.Services.ConfigureDefaultWorkflowExecutionPipeline(pipeline => WorkflowExecutionBuilderExtensions.UsePersistence(pipeline) +app.Services.ConfigureDefaultWorkflowExecutionPipeline(pipeline => pipeline.UsePersistence() .UseActivityScheduler() ); diff --git a/src/samples/console/Elsa.Samples.Console2/Program.cs b/src/samples/console/Elsa.Samples.Console2/Program.cs index b71af86ce..0397e9005 100644 --- a/src/samples/console/Elsa.Samples.Console2/Program.cs +++ b/src/samples/console/Elsa.Samples.Console2/Program.cs @@ -28,7 +28,7 @@ typeSystem.Register("Variable<>", typeof(Variable<>)); typeSystem.Register(); typeSystem.Register(); typeSystem.Register(); -typeSystem.Register(); +typeSystem.Register(); typeSystem.Register(); functionActivityRegistry.RegisterFunction("print", nameof(WriteLine), new[] { nameof(WriteLine.Text) });