| | | 1 | | using System.Runtime.CompilerServices; |
| | | 2 | | using Elsa.Common.Models; |
| | | 3 | | using Elsa.Extensions; |
| | | 4 | | using Elsa.Workflows.Attributes; |
| | | 5 | | using Elsa.Workflows.Management; |
| | | 6 | | using Elsa.Workflows.Models; |
| | | 7 | | using Elsa.Workflows.Options; |
| | | 8 | | using Elsa.Workflows.Runtime.Stimuli; |
| | | 9 | | using Elsa.Workflows.UIHints; |
| | | 10 | | using JetBrains.Annotations; |
| | | 11 | | |
| | | 12 | | namespace Elsa.Workflows.Runtime.Activities; |
| | | 13 | | |
| | | 14 | | /// <summary> |
| | | 15 | | /// Creates a new workflow instance of the specified workflow and dispatches it for execution. |
| | | 16 | | /// </summary> |
| | | 17 | | [Activity("Elsa", "Composition", "Create a new workflow instance of the specified workflow and execute it.", Kind = Acti |
| | | 18 | | [UsedImplicitly] |
| | | 19 | | public class ExecuteWorkflow : Activity<ExecuteWorkflowResult> |
| | | 20 | | { |
| | | 21 | | /// <inheritdoc /> |
| | 126 | 22 | | public ExecuteWorkflow([CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : base(source, l |
| | | 23 | | { |
| | 126 | 24 | | } |
| | | 25 | | |
| | | 26 | | /// <summary> |
| | | 27 | | /// The definition ID of the workflow to execute. |
| | | 28 | | /// </summary> |
| | | 29 | | [Input( |
| | | 30 | | DisplayName = "Workflow Definition", |
| | | 31 | | Description = "The definition ID of the workflow to execute.", |
| | | 32 | | UIHint = InputUIHints.WorkflowDefinitionPicker |
| | | 33 | | )] |
| | 352 | 34 | | public Input<string> WorkflowDefinitionId { get; set; } = null!; |
| | | 35 | | |
| | | 36 | | /// <summary> |
| | | 37 | | /// The correlation ID to associate the workflow with. |
| | | 38 | | /// </summary> |
| | | 39 | | [Input( |
| | | 40 | | DisplayName = "Correlation ID", |
| | | 41 | | Description = "The correlation ID to associate the workflow with." |
| | | 42 | | )] |
| | 247 | 43 | | public Input<string?> CorrelationId { get; set; } = null!; |
| | | 44 | | |
| | | 45 | | /// <summary> |
| | | 46 | | /// The input to send to the workflow. |
| | | 47 | | /// </summary> |
| | | 48 | | [Input(Description = "The input to send to the workflow.")] |
| | 265 | 49 | | public Input<IDictionary<string, object>?> Input { get; set; } = null!; |
| | | 50 | | |
| | | 51 | | /// <summary> |
| | | 52 | | /// True to wait for the child workflow to complete before completing this activity. If not set, the child workflow |
| | | 53 | | /// </summary> |
| | | 54 | | [Input(Description = "Wait for the child workflow to complete before completing this activity.")] |
| | 334 | 55 | | public Input<bool> WaitForCompletion { get; set; } = null!; |
| | | 56 | | |
| | | 57 | | /// <inheritdoc /> |
| | | 58 | | protected override async ValueTask ExecuteAsync(ActivityExecutionContext context) |
| | | 59 | | { |
| | 7 | 60 | | var waitForCompletion = WaitForCompletion.Get(context); |
| | 7 | 61 | | var result = await ExecuteWorkflowAsync(context, waitForCompletion); |
| | | 62 | | |
| | 7 | 63 | | if (!waitForCompletion || result.Status == WorkflowStatus.Finished) |
| | | 64 | | { |
| | 7 | 65 | | context.SetResult(result); |
| | 7 | 66 | | await context.CompleteActivityAsync(); |
| | 7 | 67 | | return; |
| | | 68 | | } |
| | | 69 | | |
| | | 70 | | // Since the child workflow is still running, we need to wait for it to complete using a bookmark. |
| | 0 | 71 | | var bookmarkOptions = new CreateBookmarkArgs |
| | 0 | 72 | | { |
| | 0 | 73 | | Callback = OnChildWorkflowCompletedAsync, |
| | 0 | 74 | | Stimulus = new ExecuteWorkflowStimulus(result.WorkflowInstanceId), |
| | 0 | 75 | | IncludeActivityInstanceId = false |
| | 0 | 76 | | }; |
| | 0 | 77 | | context.CreateBookmark(bookmarkOptions); |
| | 7 | 78 | | } |
| | | 79 | | |
| | | 80 | | private async ValueTask<ExecuteWorkflowResult> ExecuteWorkflowAsync(ActivityExecutionContext context, bool waitForCo |
| | | 81 | | { |
| | 7 | 82 | | var workflowDefinitionId = WorkflowDefinitionId.Get(context); |
| | 7 | 83 | | var workflowDefinitionService = context.GetRequiredService<IWorkflowDefinitionService>(); |
| | 7 | 84 | | var workflowGraph = await workflowDefinitionService.FindWorkflowGraphAsync(workflowDefinitionId, VersionOptions. |
| | | 85 | | |
| | 7 | 86 | | if (workflowGraph == null) |
| | 0 | 87 | | throw new($"No published version of workflow definition with ID {workflowDefinitionId} found."); |
| | | 88 | | |
| | 7 | 89 | | var parentInstanceId = context.WorkflowExecutionContext.Id; |
| | 7 | 90 | | var input = Input.GetOrDefault(context) ?? new Dictionary<string, object>(); |
| | 7 | 91 | | var correlationId = CorrelationId.GetOrDefault(context); |
| | 7 | 92 | | var workflowInvoker = context.GetRequiredService<IWorkflowInvoker>(); |
| | 7 | 93 | | var identityGenerator = context.GetRequiredService<IIdentityGenerator>(); |
| | 7 | 94 | | var properties = new Dictionary<string, object> |
| | 7 | 95 | | { |
| | 7 | 96 | | ["ParentInstanceId"] = parentInstanceId |
| | 7 | 97 | | }; |
| | | 98 | | |
| | | 99 | | // If we need to wait for the child workflow to complete, set the property. This will be used by the ResumeExecu |
| | 7 | 100 | | if (waitForCompletion) |
| | 4 | 101 | | properties["WaitForCompletion"] = true; |
| | | 102 | | |
| | 7 | 103 | | input["ParentInstanceId"] = parentInstanceId; |
| | | 104 | | |
| | 7 | 105 | | var options = new RunWorkflowOptions |
| | 7 | 106 | | { |
| | 7 | 107 | | ParentWorkflowInstanceId = parentInstanceId, |
| | 7 | 108 | | Input = input, |
| | 7 | 109 | | Properties = properties, |
| | 7 | 110 | | CorrelationId = correlationId, |
| | 7 | 111 | | WorkflowInstanceId = identityGenerator.GenerateId() |
| | 7 | 112 | | }; |
| | | 113 | | |
| | 7 | 114 | | var workflowResult = await workflowInvoker.InvokeAsync(workflowGraph, options, context.CancellationToken); |
| | 7 | 115 | | var info = new ExecuteWorkflowResult |
| | 7 | 116 | | { |
| | 7 | 117 | | WorkflowInstanceId = options.WorkflowInstanceId, |
| | 7 | 118 | | Status = workflowResult.WorkflowState.Status, |
| | 7 | 119 | | SubStatus = workflowResult.WorkflowState.SubStatus, |
| | 7 | 120 | | Output = workflowResult.WorkflowState.Output |
| | 7 | 121 | | }; |
| | | 122 | | |
| | 7 | 123 | | return info; |
| | 7 | 124 | | } |
| | | 125 | | |
| | | 126 | | private async ValueTask OnChildWorkflowCompletedAsync(ActivityExecutionContext context) |
| | | 127 | | { |
| | 0 | 128 | | var input = context.WorkflowInput; |
| | 0 | 129 | | context.Set(Result, input); |
| | 0 | 130 | | await context.CompleteActivityAsync(); |
| | 0 | 131 | | } |
| | | 132 | | } |