< Summary

Information
Class: Elsa.Workflows.Runtime.Activities.ExecuteWorkflow
Assembly: Elsa.Workflows.Runtime
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Runtime/Activities/ExecuteWorkflow.cs
Line coverage
79%
Covered lines: 47
Uncovered lines: 12
Coverable lines: 59
Total lines: 132
Line coverage: 79.6%
Branch coverage
80%
Covered branches: 8
Total branches: 10
Branch coverage: 80%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_WorkflowDefinitionId()100%11100%
get_CorrelationId()100%11100%
get_Input()100%11100%
get_WaitForCompletion()100%11100%
ExecuteAsync()75%6450%
ExecuteWorkflowAsync()83.33%6697.14%
OnChildWorkflowCompletedAsync()100%210%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Runtime/Activities/ExecuteWorkflow.cs

#LineLine coverage
 1using System.Runtime.CompilerServices;
 2using Elsa.Common.Models;
 3using Elsa.Extensions;
 4using Elsa.Workflows.Attributes;
 5using Elsa.Workflows.Management;
 6using Elsa.Workflows.Models;
 7using Elsa.Workflows.Options;
 8using Elsa.Workflows.Runtime.Stimuli;
 9using Elsa.Workflows.UIHints;
 10using JetBrains.Annotations;
 11
 12namespace 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]
 19public class ExecuteWorkflow : Activity<ExecuteWorkflowResult>
 20{
 21    /// <inheritdoc />
 12622    public ExecuteWorkflow([CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : base(source, l
 23    {
 12624    }
 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    )]
 35234    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    )]
 24743    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.")]
 26549    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.")]
 33455    public Input<bool> WaitForCompletion { get; set; } = null!;
 56
 57    /// <inheritdoc />
 58    protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
 59    {
 760        var waitForCompletion = WaitForCompletion.Get(context);
 761        var result = await ExecuteWorkflowAsync(context, waitForCompletion);
 62
 763        if (!waitForCompletion || result.Status == WorkflowStatus.Finished)
 64        {
 765            context.SetResult(result);
 766            await context.CompleteActivityAsync();
 767            return;
 68        }
 69
 70        // Since the child workflow is still running, we need to wait for it to complete using a bookmark.
 071        var bookmarkOptions = new CreateBookmarkArgs
 072        {
 073            Callback = OnChildWorkflowCompletedAsync,
 074            Stimulus = new ExecuteWorkflowStimulus(result.WorkflowInstanceId),
 075            IncludeActivityInstanceId = false
 076        };
 077        context.CreateBookmark(bookmarkOptions);
 778    }
 79
 80    private async ValueTask<ExecuteWorkflowResult> ExecuteWorkflowAsync(ActivityExecutionContext context, bool waitForCo
 81    {
 782        var workflowDefinitionId = WorkflowDefinitionId.Get(context);
 783        var workflowDefinitionService = context.GetRequiredService<IWorkflowDefinitionService>();
 784        var workflowGraph = await workflowDefinitionService.FindWorkflowGraphAsync(workflowDefinitionId, VersionOptions.
 85
 786        if (workflowGraph == null)
 087            throw new($"No published version of workflow definition with ID {workflowDefinitionId} found.");
 88
 789        var parentInstanceId = context.WorkflowExecutionContext.Id;
 790        var input = Input.GetOrDefault(context) ?? new Dictionary<string, object>();
 791        var correlationId = CorrelationId.GetOrDefault(context);
 792        var workflowInvoker = context.GetRequiredService<IWorkflowInvoker>();
 793        var identityGenerator = context.GetRequiredService<IIdentityGenerator>();
 794        var properties = new Dictionary<string, object>
 795        {
 796            ["ParentInstanceId"] = parentInstanceId
 797        };
 98
 99        // If we need to wait for the child workflow to complete, set the property. This will be used by the ResumeExecu
 7100        if (waitForCompletion)
 4101            properties["WaitForCompletion"] = true;
 102
 7103        input["ParentInstanceId"] = parentInstanceId;
 104
 7105        var options = new RunWorkflowOptions
 7106        {
 7107            ParentWorkflowInstanceId = parentInstanceId,
 7108            Input = input,
 7109            Properties = properties,
 7110            CorrelationId = correlationId,
 7111            WorkflowInstanceId = identityGenerator.GenerateId()
 7112        };
 113
 7114        var workflowResult = await workflowInvoker.InvokeAsync(workflowGraph, options, context.CancellationToken);
 7115        var info = new ExecuteWorkflowResult
 7116        {
 7117            WorkflowInstanceId = options.WorkflowInstanceId,
 7118            Status = workflowResult.WorkflowState.Status,
 7119            SubStatus = workflowResult.WorkflowState.SubStatus,
 7120            Output = workflowResult.WorkflowState.Output
 7121        };
 122
 7123        return info;
 7124    }
 125
 126    private async ValueTask OnChildWorkflowCompletedAsync(ActivityExecutionContext context)
 127    {
 0128        var input = context.WorkflowInput;
 0129        context.Set(Result, input);
 0130        await context.CompleteActivityAsync();
 0131    }
 132}