From bfefd3f23705f040dd83cb7529a93d7e673d6ef9 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Fri, 2 Sep 2022 19:02:24 +0200 Subject: [PATCH] V3 default runtime (#3285) * Incremental work on default runtime * Fix workflow rooting --- .../Elsa.WorkflowServer.Web/Program.cs | 5 +- .../ProtoActorWorkflowRuntime.cs | 9 +- .../Elsa.ProtoActor/Protos/Messages.proto | 1 + .../Endpoints/Events/Trigger/Endpoint.cs | 5 +- .../Activities/Composite.cs | 14 +- .../OutboundActivityPortResolver.cs | 2 +- .../Implementations/WorkflowRunner.cs | 2 +- .../Elsa.Workflows.Core/Models/Bookmark.cs | 2 +- .../Elsa.Workflows.Core/Models/Workflow.cs | 2 +- .../Implementations/BookmarkManager.cs | 35 +++- .../Implementations/DefaultWorkflowRuntime.cs | 165 +++++++++++++++++- .../Services/IBookmarkManager.cs | 8 +- .../Services/IWorkflowRuntime.cs | 2 +- 13 files changed, 219 insertions(+), 33 deletions(-) diff --git a/src/bundles/Elsa.WorkflowServer.Web/Program.cs b/src/bundles/Elsa.WorkflowServer.Web/Program.cs index dad0af7b3..be4d72c96 100644 --- a/src/bundles/Elsa.WorkflowServer.Web/Program.cs +++ b/src/bundles/Elsa.WorkflowServer.Web/Program.cs @@ -15,7 +15,6 @@ using Elsa.Labels.EntityFrameworkCore.Extensions; using Elsa.Labels.EntityFrameworkCore.Sqlite; using Elsa.Labels.Extensions; using Elsa.Liquid.Extensions; -using Elsa.ProtoActor.Extensions; using Elsa.Scheduling.Extensions; using Elsa.WorkflowContexts.Extensions; using Elsa.Workflows.Api.Extensions; @@ -32,8 +31,6 @@ using Elsa.WorkflowServer.Web.Jobs; using FastEndpoints; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; -using Microsoft.Data.Sqlite; -using Proto.Persistence.Sqlite; using Event = Elsa.Workflows.Core.Activities.Event; var builder = WebApplication.CreateBuilder(args); @@ -68,7 +65,7 @@ services identity.CreateDefaultUser = true; identity.IdentityOptions = options => identitySection.Bind(options); }) - .UseRuntime(runtime => runtime.UseProtoActor(proto => proto.PersistenceProvider = _ => new SqliteProvider(new SqliteConnectionStringBuilder(dbConnectionString)))) + //.UseRuntime(runtime => runtime.UseProtoActor(proto => proto.PersistenceProvider = _ => new SqliteProvider(new SqliteConnectionStringBuilder(dbConnectionString)))) .UseJobActivities() .UseScheduling() .UseWorkflowPersistence(p => p.UseEntityFrameworkCore(ef => ef.UseSqlite(dbConnectionString))) diff --git a/src/modules/Elsa.ProtoActor/Implementations/ProtoActorWorkflowRuntime.cs b/src/modules/Elsa.ProtoActor/Implementations/ProtoActorWorkflowRuntime.cs index 17ee9d291..2684bf085 100644 --- a/src/modules/Elsa.ProtoActor/Implementations/ProtoActorWorkflowRuntime.cs +++ b/src/modules/Elsa.ProtoActor/Implementations/ProtoActorWorkflowRuntime.cs @@ -58,19 +58,20 @@ public class ProtoActorWorkflowRuntime : IWorkflowRuntime return new ResumeWorkflowResult(); } - public async Task TriggerWorkflowsAsync(object bookmarkPayload, TriggerWorkflowsOptions options, CancellationToken cancellationToken = default) + public async Task TriggerWorkflowsAsync(string bookmarkName, object bookmarkPayload, TriggerWorkflowsOptions options, CancellationToken cancellationToken = default) { var hash = _hasher.Hash(bookmarkPayload); var client = _cluster.GetBookmarkGrain(hash); - var bookmarksResponse = await client.Resolve(new ResolveBookmarksRequest(), cancellationToken); + var request = new ResolveBookmarksRequest() { BookmarkName = bookmarkName }; + var bookmarksResponse = await client.Resolve(request, cancellationToken); var bookmarks = bookmarksResponse!.Bookmarks; foreach (var bookmark in bookmarks) { var workflowInstanceId = bookmark.WorkflowInstanceId; - var resumeResult = await ResumeWorkflowAsync(workflowInstanceId, bookmark.BookmarkId, new ResumeWorkflowOptions(options.Input), cancellationToken); + var resumeResult = await ResumeWorkflowAsync(workflowInstanceId, bookmark.BookmarkId, new ResumeWorkflowOptions(options.Input), cancellationToken); } - + return new TriggerWorkflowsResult(); } } \ No newline at end of file diff --git a/src/modules/Elsa.ProtoActor/Protos/Messages.proto b/src/modules/Elsa.ProtoActor/Protos/Messages.proto index 89db25805..ab42f9eb7 100644 --- a/src/modules/Elsa.ProtoActor/Protos/Messages.proto +++ b/src/modules/Elsa.ProtoActor/Protos/Messages.proto @@ -42,6 +42,7 @@ message RemoveBookmarksByWorkflowRequest { } message ResolveBookmarksRequest { + string BookmarkName = 1; } message ResolveBookmarksResponse { diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/Events/Trigger/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/Events/Trigger/Endpoint.cs index 82e0270bc..dd0c62ff1 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/Events/Trigger/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/Events/Trigger/Endpoint.cs @@ -1,6 +1,8 @@ using System.Threading; using System.Threading.Tasks; using Elsa.Abstractions; +using Elsa.Workflows.Core.Activities; +using Elsa.Workflows.Core.Helpers; using Elsa.Workflows.Core.Models; using Elsa.Workflows.Core.Services; using Elsa.Workflows.Runtime.Services; @@ -27,7 +29,8 @@ public class Trigger : ElsaEndpoint public override async Task HandleAsync(Request request, CancellationToken cancellationToken) { var eventBookmark = new EventBookmarkData(request.EventName); - var result = await _workflowRuntime.TriggerWorkflowsAsync(eventBookmark, new TriggerWorkflowsOptions(), cancellationToken); + var bookmarkName = ActivityTypeNameHelper.GenerateTypeName(); + var result = await _workflowRuntime.TriggerWorkflowsAsync(bookmarkName, eventBookmark, new TriggerWorkflowsOptions(), cancellationToken); if (!HttpContext.Response.HasStarted) { diff --git a/src/modules/Elsa.Workflows.Core/Activities/Composite.cs b/src/modules/Elsa.Workflows.Core/Activities/Composite.cs index 1e9a996b9..ed7f1ec29 100644 --- a/src/modules/Elsa.Workflows.Core/Activities/Composite.cs +++ b/src/modules/Elsa.Workflows.Core/Activities/Composite.cs @@ -9,7 +9,7 @@ namespace Elsa.Workflows.Core.Activities; /// Represents a composite activity that has a single activity. Like a workflow, but without workflow-level properties. /// [Activity("Elsa", "Workflows", "Execute a root activity that you can configure yourself")] -public class Composite : Activity +public class Composite : ActivityBase { /// /// The activity to schedule when this activity executes. @@ -22,7 +22,10 @@ public class Composite : Activity context.ScheduleActivity(Root, OnCompletedAsync); } - protected virtual ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) => ValueTask.CompletedTask; + protected virtual async ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) + { + await context.CompleteActivityAsync(); + } protected static Inline From(Func activity) => new(activity); protected static Inline From(Func activity) => new(activity); @@ -37,7 +40,7 @@ public class Composite : Activity /// /// Represents a composite activity that has a single activity and returns a result. /// -public class Composite : Activity +public class Composite : ActivityBase { /// /// The activity to schedule when this activity executes. @@ -50,7 +53,10 @@ public class Composite : Activity context.ScheduleActivity(Root, OnCompletedAsync); } - protected virtual ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) => ValueTask.CompletedTask; + protected virtual async ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) + { + await context.CompleteActivityAsync(); + } protected static Inline From(Func activity) => new(activity); protected static Inline From(Func activity) => new(activity); diff --git a/src/modules/Elsa.Workflows.Core/ActivityNodeResolvers/OutboundActivityPortResolver.cs b/src/modules/Elsa.Workflows.Core/ActivityNodeResolvers/OutboundActivityPortResolver.cs index 7cd803f7e..93721607f 100644 --- a/src/modules/Elsa.Workflows.Core/ActivityNodeResolvers/OutboundActivityPortResolver.cs +++ b/src/modules/Elsa.Workflows.Core/ActivityNodeResolvers/OutboundActivityPortResolver.cs @@ -8,7 +8,7 @@ namespace Elsa.Workflows.Core.ActivityNodeResolvers; public class OutboundActivityPortResolver : IActivityPortResolver { public int Priority => -1; - public bool GetSupportsActivity(IActivity activity) => activity is Activity; + public bool GetSupportsActivity(IActivity activity) => true; public ValueTask> GetPortsAsync(IActivity activity, CancellationToken cancellationToken = default) => new(GetSinglePorts(activity) diff --git a/src/modules/Elsa.Workflows.Core/Implementations/WorkflowRunner.cs b/src/modules/Elsa.Workflows.Core/Implementations/WorkflowRunner.cs index 271554092..18f916c37 100644 --- a/src/modules/Elsa.Workflows.Core/Implementations/WorkflowRunner.cs +++ b/src/modules/Elsa.Workflows.Core/Implementations/WorkflowRunner.cs @@ -141,7 +141,7 @@ public class WorkflowRunner : IWorkflowRunner ExecuteActivityDelegate? executeActivityDelegate, CancellationToken cancellationToken) { - var root = workflow.Root; + var root = workflow; // Build graph. var graph = await _activityWalker.WalkAsync(root, cancellationToken); diff --git a/src/modules/Elsa.Workflows.Core/Models/Bookmark.cs b/src/modules/Elsa.Workflows.Core/Models/Bookmark.cs index a51cc0dfe..9fe682928 100644 --- a/src/modules/Elsa.Workflows.Core/Models/Bookmark.cs +++ b/src/modules/Elsa.Workflows.Core/Models/Bookmark.cs @@ -3,7 +3,7 @@ namespace Elsa.Workflows.Core.Models; public record Bookmark( string Id, string Name, - string Hash, + string? Hash, string? Data, string ActivityId, string ActivityInstanceId, diff --git a/src/modules/Elsa.Workflows.Core/Models/Workflow.cs b/src/modules/Elsa.Workflows.Core/Models/Workflow.cs index 9a5c2a291..9129116cb 100644 --- a/src/modules/Elsa.Workflows.Core/Models/Workflow.cs +++ b/src/modules/Elsa.Workflows.Core/Models/Workflow.cs @@ -33,7 +33,7 @@ public class Workflow : Composite, ICloneable { } - public static Workflow FromActivity(IActivity root) => new(root); + public static Workflow FromActivity(IActivity root) => root is Workflow workflow ? workflow : new(root); /// /// Creates a new memory register initialized with this workflow's variables. diff --git a/src/modules/Elsa.Workflows.Runtime/Implementations/BookmarkManager.cs b/src/modules/Elsa.Workflows.Runtime/Implementations/BookmarkManager.cs index 017149ac0..956866b92 100644 --- a/src/modules/Elsa.Workflows.Runtime/Implementations/BookmarkManager.cs +++ b/src/modules/Elsa.Workflows.Runtime/Implementations/BookmarkManager.cs @@ -1,4 +1,5 @@ using Elsa.Mediator.Services; +using Elsa.Workflows.Core.Models; using Elsa.Workflows.Persistence.Entities; using Elsa.Workflows.Persistence.Services; using Elsa.Workflows.Runtime.Notifications; @@ -17,20 +18,36 @@ public class BookmarkManager : IBookmarkManager _eventPublisher = eventPublisher; } - public async Task DeleteBookmarksAsync(IEnumerable workflowBookmarks, CancellationToken cancellationToken = default) + public async Task DeleteAsync(IEnumerable bookmarks, CancellationToken cancellationToken = default) { - var list = workflowBookmarks.ToList(); + var list = bookmarks.ToList(); var ids = list.Select(x => x.Id).ToList(); - var bookmarks = list.Select(x => x.ToBookmark()).ToList(); await _bookmarkStore.DeleteManyAsync(ids, cancellationToken); - await _eventPublisher.PublishAsync(new WorkflowBookmarksDeleted(bookmarks), cancellationToken); + await _eventPublisher.PublishAsync(new WorkflowBookmarksDeleted(list), cancellationToken); } - public async Task SaveBookmarksAsync(IEnumerable workflowBookmarks, CancellationToken cancellationToken = default) + public async Task SaveAsync(WorkflowInstance workflowInstance, IEnumerable bookmarks, CancellationToken cancellationToken = default) { - var list = workflowBookmarks.ToList(); - var bookmarks = list.Select(x => x.ToBookmark()).ToList(); - await _bookmarkStore.SaveManyAsync(list, cancellationToken); - await _eventPublisher.PublishAsync(new WorkflowBookmarksSaved(bookmarks), cancellationToken); + var list = bookmarks.ToList(); + var workflowBookmarks = list.Select(x => WorkflowBookmark.FromBookmark(x, workflowInstance)).ToList(); + await _bookmarkStore.SaveManyAsync(workflowBookmarks, cancellationToken); + await _eventPublisher.PublishAsync(new WorkflowBookmarksSaved(list), cancellationToken); + } + + public async Task FindByIdAsync(string id, CancellationToken cancellationToken) + { + var workflowBookmark = await _bookmarkStore.FindByIdAsync(id, cancellationToken); + return workflowBookmark?.ToBookmark(); + } + + public async Task> FindManyByWorkflowInstanceIdAsync(string workflowInstanceId, CancellationToken cancellationToken = default) + { + var workflowBookmarks = await _bookmarkStore.FindManyByWorkflowInstanceIdAsync(workflowInstanceId, cancellationToken); + return workflowBookmarks.Select(x => x.ToBookmark()); + } + + public async Task> FindManyByHashAsync(string bookmarkName, string hash, CancellationToken cancellationToken = default) + { + return await _bookmarkStore.FindManyAsync(bookmarkName, hash, cancellationToken); } } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Runtime/Implementations/DefaultWorkflowRuntime.cs b/src/modules/Elsa.Workflows.Runtime/Implementations/DefaultWorkflowRuntime.cs index bce835d97..ba5ff4979 100644 --- a/src/modules/Elsa.Workflows.Runtime/Implementations/DefaultWorkflowRuntime.cs +++ b/src/modules/Elsa.Workflows.Runtime/Implementations/DefaultWorkflowRuntime.cs @@ -1,21 +1,178 @@ +using Elsa.Common.Services; +using Elsa.Mediator.Services; +using Elsa.Models; +using Elsa.Workflows.Core.Helpers; +using Elsa.Workflows.Core.Models; +using Elsa.Workflows.Core.Services; +using Elsa.Workflows.Core.State; +using Elsa.Workflows.Persistence.Entities; +using Elsa.Workflows.Persistence.Services; +using Elsa.Workflows.Runtime.Models; +using Elsa.Workflows.Runtime.Notifications; using Elsa.Workflows.Runtime.Services; +using Open.Linq.AsyncExtensions; namespace Elsa.Workflows.Runtime.Implementations; public class DefaultWorkflowRuntime : IWorkflowRuntime { + private readonly IWorkflowRunner _workflowRunner; + private readonly IWorkflowDefinitionService _workflowDefinitionService; + private readonly IWorkflowInstanceStore _workflowInstanceStore; + private readonly IBookmarkManager _bookmarkManager; + private readonly IHasher _hasher; + private readonly IEventPublisher _eventPublisher; + private readonly ISystemClock _systemClock; + + public DefaultWorkflowRuntime( + IWorkflowRunner workflowRunner, + IWorkflowDefinitionService workflowDefinitionService, + IWorkflowInstanceStore workflowInstanceStore, + IBookmarkManager bookmarkManager, + IHasher hasher, + IEventPublisher eventPublisher, + ISystemClock systemClock) + { + _workflowRunner = workflowRunner; + _workflowDefinitionService = workflowDefinitionService; + _workflowInstanceStore = workflowInstanceStore; + _bookmarkManager = bookmarkManager; + _hasher = hasher; + _eventPublisher = eventPublisher; + _systemClock = systemClock; + } + public async Task StartWorkflowAsync(string definitionId, StartWorkflowOptions options, CancellationToken cancellationToken = default) { - throw new NotImplementedException(); + var input = options.Input; + var versionOptions = options.VersionOptions; + var workflowDefinition = await _workflowDefinitionService.FindAsync(definitionId, versionOptions, cancellationToken); + + if (workflowDefinition == null) + throw new Exception("Specified workflow definition and version does not exist"); + + var workflow = await _workflowDefinitionService.MaterializeWorkflowAsync(workflowDefinition, cancellationToken); + var workflowResult = await _workflowRunner.RunAsync(workflow, input, cancellationToken); + var workflowState = workflowResult.WorkflowState; + var finished = workflowResult.WorkflowState.Status == WorkflowStatus.Finished; + + var workflowInstance = await SaveWorkflowInstanceAsync(workflowDefinition, workflowState, cancellationToken); + await UpdateBookmarksAsync(workflowInstance, new List(), workflowResult.Bookmarks, cancellationToken); + + return new StartWorkflowResult(workflowInstance.Id); } public async Task ResumeWorkflowAsync(string instanceId, string bookmarkId, ResumeWorkflowOptions options, CancellationToken cancellationToken = default) { - throw new NotImplementedException(); + var workflowInstance = await _workflowInstanceStore.FindByIdAsync(instanceId, cancellationToken); + + if (workflowInstance == null) + throw new Exception($"Workflow instance {instanceId} not found"); + + var workflowDefinition = await _workflowDefinitionService.FindAsync(workflowInstance.DefinitionId, VersionOptions.SpecificVersion(workflowInstance.Version), cancellationToken); + + if (workflowDefinition == null) + throw new Exception("Specified workflow definition and version does not exist"); + + var input = options.Input; + + var existingBookmarks = await _bookmarkManager.FindManyByWorkflowInstanceIdAsync(workflowInstance.Id, cancellationToken).ToList(); + var bookmark = existingBookmarks.FirstOrDefault(x => x.Id == bookmarkId); + + if (bookmark == null) + throw new Exception("Bookmark not found"); + + var workflow = await _workflowDefinitionService.MaterializeWorkflowAsync(workflowDefinition, cancellationToken); + var workflowState = workflowInstance.WorkflowState; + var workflowResult = await _workflowRunner.RunAsync(workflow, workflowState, bookmark, input, cancellationToken); + var finished = workflowResult.WorkflowState.Status == WorkflowStatus.Finished; + + workflowInstance = await SaveWorkflowInstanceAsync(workflowDefinition, workflowState, cancellationToken); + await UpdateBookmarksAsync(workflowInstance, existingBookmarks, workflowResult.Bookmarks, cancellationToken); + + return new ResumeWorkflowResult(); } - public Task TriggerWorkflowsAsync(object bookmarkPayload, TriggerWorkflowsOptions options, CancellationToken cancellationToken = default) + public async Task TriggerWorkflowsAsync(string bookmarkName, object bookmarkPayload, TriggerWorkflowsOptions options, CancellationToken cancellationToken = default) { - throw new NotImplementedException(); + var hash = _hasher.Hash(bookmarkPayload); + var bookmarks = await _bookmarkManager.FindManyByHashAsync(bookmarkName, hash, cancellationToken); + + foreach (var bookmark in bookmarks) + { + var workflowInstanceId = bookmark.WorkflowInstanceId; + var resumeResult = await ResumeWorkflowAsync(workflowInstanceId, bookmark.Id, new ResumeWorkflowOptions(options.Input), cancellationToken); + } + + return new TriggerWorkflowsResult(); + } + + private async Task SaveWorkflowInstanceAsync(WorkflowDefinition workflowDefinition, WorkflowState workflowState, CancellationToken cancellationToken) + { + var workflowInstance = FromWorkflowState(workflowState, workflowDefinition); + await _workflowInstanceStore.SaveAsync(workflowInstance, cancellationToken); + return workflowInstance; + } + + private WorkflowInstance FromWorkflowState(WorkflowState workflowState, WorkflowDefinition workflowDefinition) + { + var workflowInstance = new WorkflowInstance + { + Id = workflowState.Id, + DefinitionId = workflowDefinition.DefinitionId, + DefinitionVersionId = workflowDefinition.Id, + Version = workflowDefinition.Version, + WorkflowState = workflowState, + Status = workflowState.Status, + SubStatus = workflowState.SubStatus, + CorrelationId = workflowState.CorrelationId, + Name = null, + }; + + // Update timestamps. + var now = _systemClock.UtcNow; + + if (workflowInstance.Status == WorkflowStatus.Finished) + { + switch (workflowInstance.SubStatus) + { + case WorkflowSubStatus.Cancelled: + workflowInstance.CancelledAt = now; + break; + case WorkflowSubStatus.Faulted: + workflowInstance.FaultedAt = now; + break; + case WorkflowSubStatus.Finished: + workflowInstance.FinishedAt = now; + break; + } + } + + return workflowInstance; + } + + private async Task UpdateBookmarksAsync(WorkflowInstance workflowInstance, ICollection previousBookmarks, ICollection newBookmarks, CancellationToken cancellationToken) + { + await RemoveBookmarksAsync(previousBookmarks, cancellationToken); + await StoreBookmarksAsync(workflowInstance, newBookmarks, cancellationToken); + await PublishChangedBookmarksAsync(workflowInstance.WorkflowState, previousBookmarks, newBookmarks, cancellationToken); + } + + private async Task StoreBookmarksAsync(WorkflowInstance workflowInstance, ICollection bookmarks, CancellationToken cancellationToken) + { + await _bookmarkManager.SaveAsync(workflowInstance, bookmarks, cancellationToken); + } + + private async Task RemoveBookmarksAsync(IEnumerable bookmarks, CancellationToken cancellationToken) + { + await _bookmarkManager.DeleteAsync(bookmarks, cancellationToken); + } + + private async Task PublishChangedBookmarksAsync(WorkflowState workflowState, ICollection originalBookmarks, ICollection updatedBookmarks, CancellationToken cancellationToken) + { + var diff = Diff.For(originalBookmarks, updatedBookmarks); + var removedBookmarks = diff.Removed; + var createdBookmarks = diff.Added; + await _eventPublisher.PublishAsync(new WorkflowBookmarksIndexed(new IndexedWorkflowBookmarks(workflowState, createdBookmarks, removedBookmarks)), cancellationToken); } } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Runtime/Services/IBookmarkManager.cs b/src/modules/Elsa.Workflows.Runtime/Services/IBookmarkManager.cs index 1f84e4c48..6626757a6 100644 --- a/src/modules/Elsa.Workflows.Runtime/Services/IBookmarkManager.cs +++ b/src/modules/Elsa.Workflows.Runtime/Services/IBookmarkManager.cs @@ -1,3 +1,4 @@ +using Elsa.Workflows.Core.Models; using Elsa.Workflows.Persistence.Entities; namespace Elsa.Workflows.Runtime.Services; @@ -7,6 +8,9 @@ namespace Elsa.Workflows.Runtime.Services; /// public interface IBookmarkManager { - Task DeleteBookmarksAsync(IEnumerable workflowBookmarks, CancellationToken cancellationToken = default); - Task SaveBookmarksAsync(IEnumerable workflowBookmarks, CancellationToken cancellationToken = default); + Task DeleteAsync(IEnumerable bookmarks, CancellationToken cancellationToken = default); + Task SaveAsync(WorkflowInstance workflowInstance, IEnumerable bookmarks, CancellationToken cancellationToken = default); + Task FindByIdAsync(string id, CancellationToken cancellationToken = default); + Task> FindManyByWorkflowInstanceIdAsync(string workflowInstanceId, CancellationToken cancellationToken = default); + Task> FindManyByHashAsync(string bookmarkName, string hash, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Runtime/Services/IWorkflowRuntime.cs b/src/modules/Elsa.Workflows.Runtime/Services/IWorkflowRuntime.cs index c0e52ae5b..256ea3687 100644 --- a/src/modules/Elsa.Workflows.Runtime/Services/IWorkflowRuntime.cs +++ b/src/modules/Elsa.Workflows.Runtime/Services/IWorkflowRuntime.cs @@ -8,7 +8,7 @@ public interface IWorkflowRuntime { Task StartWorkflowAsync(string definitionId, StartWorkflowOptions options, CancellationToken cancellationToken = default); Task ResumeWorkflowAsync(string instanceId, string bookmarkId, ResumeWorkflowOptions options, CancellationToken cancellationToken = default); - Task TriggerWorkflowsAsync(object bookmarkPayload, TriggerWorkflowsOptions options, CancellationToken cancellationToken = default); + Task TriggerWorkflowsAsync(string bookmarkName, object bookmarkPayload, TriggerWorkflowsOptions options, CancellationToken cancellationToken = default); } public record StartWorkflowOptions(string? CorrelationId = default, IDictionary? Input = default, VersionOptions VersionOptions = default);