using System.Runtime.CompilerServices; using System.Text.Json.Serialization; using Elsa.Expressions.Models; using Elsa.Extensions; using Elsa.Workflows.Core.Attributes; using Elsa.Workflows.Core.Models; using Elsa.Workflows.Core.Services; using Elsa.Workflows.Runtime.Bookmarks; using Elsa.Workflows.Runtime.Notifications; using Elsa.Workflows.Runtime.Services; namespace Elsa.Workflows.Runtime.Activities; /// /// Notifies the application that a task with a given name i requested to start. /// When the application fulfilled the task, it is expected to report back to the workflow engine in order to resume the workflow. /// [Activity("Elsa", "Primitives", "Requests a given task to be run. ", Kind = ActivityKind.Action)] public class RunTask : Activity, IBookmarksPersistedHandler { private static readonly object BookmarkPropertyKey = new(); /// /// The key that is used for sending and receiving activity input. /// public const string InputKey = "RunTaskInput"; /// /// The name of the task being requested. /// [Input(Description = "The name of the task being requested.")] public Input TaskName { get; set; } = default!; /// /// The name of the task being requested. /// [Input(Description = "AnyAsync additional parameters to send to the task.")] public Input TaskParams { get; set; } = default!; /// [JsonConstructor] public RunTask() { } /// public RunTask(MemoryBlockReference output, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(output, source, line) { } /// public RunTask(Output? output, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(output, source, line) { } /// public RunTask(string taskName, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(new Literal(taskName), source, line) { } /// public RunTask(Func taskName, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(new DelegateBlockReference(taskName), source, line) { } /// public RunTask(Func taskName, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(new DelegateBlockReference(taskName), source, line) { } /// public RunTask(Variable taskName, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line) => TaskName = new Input(taskName); /// public RunTask(Literal taskName, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line) => TaskName = new Input(taskName); /// protected override void Execute(ActivityExecutionContext context) { var taskName = TaskName.Get(context); var identityGenerator = context.GetRequiredService(); var taskId = identityGenerator.GenerateId(); var payload = new RunTaskBookmarkPayload(taskId); context.CreateBookmark(payload, ResumeAsync); context.TransientProperties[BookmarkPropertyKey] = payload; } private async ValueTask ResumeAsync(ActivityExecutionContext context) { var input = context.GetInput(InputKey); context.Set(Result, input); await context.CompleteActivityAsync(); } async ValueTask IBookmarksPersistedHandler.BookmarksPersistedAsync(ActivityExecutionContext context) { var bookmark = (RunTaskBookmarkPayload)context.TransientProperties[BookmarkPropertyKey]; var taskParams = TaskParams.TryGet(context); var taskName = TaskName.Get(context); var notification = new RunTaskRequest(bookmark.TaskId, taskName, taskParams); var dispatcher = context.GetRequiredService(); await dispatcher.DispatchAsync(notification, context.CancellationToken); } }