< Summary

Information
Class: Elsa.Workflows.WorkflowRunner
Assembly: Elsa.Workflows.Core
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Services/WorkflowRunner.cs
Line coverage
82%
Covered lines: 117
Uncovered lines: 24
Coverable lines: 141
Total lines: 259
Line coverage: 82.9%
Branch coverage
71%
Covered branches: 54
Total branches: 76
Branch coverage: 71%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
RunAsync()100%11100%
RunAsync()100%210%
RunAsync()100%210%
RunAsync()100%11100%
RunAsync()100%210%
RunAsync()100%2020100%
RunAsync()100%11100%
RunAsync()100%11100%
RunAsync()50%765078.26%
RunAsync()90%1010100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Services/WorkflowRunner.cs

#LineLine coverage
 1using Elsa.Extensions;
 2using Elsa.Mediator.Contracts;
 3using Elsa.Workflows.Activities;
 4using Elsa.Workflows.CommitStates;
 5using Elsa.Workflows.Memory;
 6using Elsa.Workflows.Models;
 7using Elsa.Workflows.Notifications;
 8using Elsa.Workflows.Options;
 9using Elsa.Workflows.State;
 10using Elsa.Workflows.Telemetry;
 11using Microsoft.Extensions.Logging;
 12
 13namespace Elsa.Workflows;
 14
 15/// <inheritdoc />
 49516public class WorkflowRunner(
 49517    IServiceProvider serviceProvider,
 49518    IWorkflowExecutionPipeline pipeline,
 49519    IWorkflowStateExtractor workflowStateExtractor,
 49520    IWorkflowBuilderFactory workflowBuilderFactory,
 49521    IWorkflowGraphBuilder workflowGraphBuilder,
 49522    IIdentityGenerator identityGenerator,
 49523    INotificationSender notificationSender,
 49524    ILoggerStateGenerator<WorkflowExecutionContext> loggerStateGenerator,
 49525    ICommitStateHandler commitStateHandler,
 49526    ILogger<WorkflowRunner> logger)
 27    : IWorkflowRunner
 28{
 29    /// <inheritdoc />
 30    public async Task<RunWorkflowResult> RunAsync(IActivity activity, RunWorkflowOptions? options = null, CancellationTo
 31    {
 11032        var workflow = Workflow.FromActivity(activity);
 11033        var workflowGraph = await workflowGraphBuilder.BuildAsync(workflow, cancellationToken);
 11034        return await RunAsync(workflowGraph, options, cancellationToken);
 11035    }
 36
 37    /// <inheritdoc />
 38    public async Task<RunWorkflowResult> RunAsync(IWorkflow workflow, RunWorkflowOptions? options = null, CancellationTo
 39    {
 040        var builder = workflowBuilderFactory.CreateBuilder();
 041        var workflowDefinition = await builder.BuildWorkflowAsync(workflow, cancellationToken);
 042        return await RunAsync(workflowDefinition, options, cancellationToken);
 043    }
 44
 45    /// <inheritdoc />
 46    public async Task<RunWorkflowResult<TResult>> RunAsync<TResult>(WorkflowBase<TResult> workflow, RunWorkflowOptions? 
 47    {
 048        var result = await RunAsync((IWorkflow)workflow, options, cancellationToken);
 049        return new(result.WorkflowExecutionContext, result.WorkflowState, result.Workflow, (TResult)result.Result!, resu
 050    }
 51
 52    /// <inheritdoc />
 53    public async Task<RunWorkflowResult> RunAsync<T>(RunWorkflowOptions? options = null, CancellationToken cancellationT
 54    {
 255        var builder = workflowBuilderFactory.CreateBuilder();
 256        var workflowDefinition = await builder.BuildWorkflowAsync<T>(cancellationToken);
 257        return await RunAsync(workflowDefinition, options, cancellationToken);
 258    }
 59
 60    /// <inheritdoc />
 61    public async Task<TResult> RunAsync<T, TResult>(RunWorkflowOptions? options = null, CancellationToken cancellationTo
 62    {
 063        var builder = workflowBuilderFactory.CreateBuilder();
 064        var workflow = await builder.BuildWorkflowAsync<T>(cancellationToken);
 065        var result = await RunAsync(workflow, options, cancellationToken);
 066        return (TResult)result.Result!;
 067    }
 68
 69    /// <inheritdoc />
 70    public async Task<RunWorkflowResult> RunAsync(WorkflowGraph workflowGraph, RunWorkflowOptions? options = null, Cance
 71    {
 72        // Set up a workflow execution context.
 37273        var instanceId = options?.WorkflowInstanceId ?? identityGenerator.GenerateId();
 37274        var input = options?.Input;
 37275        var properties = options?.Properties;
 37276        var correlationId = options?.CorrelationId;
 37277        var triggerActivityId = options?.TriggerActivityId;
 37278        var parentWorkflowInstanceId = options?.ParentWorkflowInstanceId;
 37279        var workflowExecutionContext = await WorkflowExecutionContext.CreateAsync(
 37280            serviceProvider,
 37281            workflowGraph,
 37282            instanceId,
 37283            correlationId,
 37284            parentWorkflowInstanceId,
 37285            input,
 37286            properties,
 37287            null,
 37288            triggerActivityId,
 37289            cancellationToken);
 90
 91        // Schedule the first activity.
 37292        workflowExecutionContext.ScheduleWorkflow(
 37293            schedulingActivityExecutionId: options?.SchedulingActivityExecutionId,
 37294            schedulingWorkflowInstanceId: options?.SchedulingWorkflowInstanceId,
 37295            schedulingCallStackDepth: options?.SchedulingCallStackDepth);
 96
 37297        return await RunAsync(workflowExecutionContext);
 37298    }
 99
 100    /// <inheritdoc />
 101    public async Task<RunWorkflowResult> RunAsync(Workflow workflow, RunWorkflowOptions? options = null, CancellationTok
 102    {
 2103        var workflowGraph = await workflowGraphBuilder.BuildAsync(workflow, cancellationToken);
 2104        return await RunAsync(workflowGraph, options, cancellationToken);
 2105    }
 106
 107    /// <inheritdoc />
 108    public async Task<RunWorkflowResult> RunAsync(Workflow workflow, WorkflowState workflowState, RunWorkflowOptions? op
 109    {
 2110        var workflowGraph = await workflowGraphBuilder.BuildAsync(workflow, cancellationToken);
 2111        return await RunAsync(workflowGraph, workflowState, options, cancellationToken);
 2112    }
 113
 114    /// <inheritdoc />
 115    public async Task<RunWorkflowResult> RunAsync(WorkflowGraph workflowGraph, WorkflowState workflowState, RunWorkflowO
 116    {
 117        // Create a workflow execution context.
 129118        var input = options?.Input;
 129119        var variables = options?.Variables;
 129120        var properties = options?.Properties;
 129121        var correlationId = options?.CorrelationId ?? workflowState.CorrelationId;
 129122        var triggerActivityId = options?.TriggerActivityId;
 129123        var parentWorkflowInstanceId = options?.ParentWorkflowInstanceId;
 129124        var workflowExecutionContext = await WorkflowExecutionContext.CreateAsync(
 129125            serviceProvider,
 129126            workflowGraph,
 129127            workflowState,
 129128            correlationId,
 129129            parentWorkflowInstanceId,
 129130            input,
 129131            properties,
 129132            null,
 129133            triggerActivityId,
 129134            cancellationToken);
 135
 129136        var bookmarkId = options?.BookmarkId;
 129137        var activityHandle = options?.ActivityHandle;
 138
 129139        if (!string.IsNullOrEmpty(bookmarkId))
 140        {
 70141            var bookmark = workflowState.Bookmarks.FirstOrDefault(x => x.Id == bookmarkId);
 142
 35143            if (bookmark != null)
 35144                workflowExecutionContext.ScheduleBookmark(bookmark);
 145        }
 94146        else if (activityHandle != null)
 147        {
 0148            if (!string.IsNullOrEmpty(activityHandle.ActivityInstanceId))
 149            {
 0150                var activityExecutionContext = workflowExecutionContext.ActivityExecutionContexts.FirstOrDefault(x => x.
 0151                                               ?? throw new("No activity execution context found with the specified ID."
 0152                workflowExecutionContext.ScheduleActivityExecutionContext(activityExecutionContext);
 153            }
 154            else
 155            {
 0156                var activity = workflowExecutionContext.FindActivity(activityHandle);
 0157                if (activity != null) workflowExecutionContext.ScheduleActivity(activity);
 158            }
 159        }
 94160        else if (workflowExecutionContext.Scheduler.HasAny)
 161        {
 162            // Do nothing. The scheduler already has activities to schedule.
 163        }
 164        else
 165        {
 166            // Check if there are any interrupted activities.
 94167            var interruptedActivityExecutionContexts = workflowExecutionContext.ActivityExecutionContexts.Where(x => x.I
 168
 94169            if (interruptedActivityExecutionContexts.Count > 0)
 170            {
 171                // Schedule the interrupted activities.
 0172                foreach (var pendingActivityExecutionContext in interruptedActivityExecutionContexts)
 0173                    workflowExecutionContext.ScheduleActivityExecutionContext(pendingActivityExecutionContext);
 174            }
 175            else
 176            {
 177                // Nothing was scheduled. Schedule the workflow itself.
 94178                var vars = variables?.Select(x => new Variable(x.Key, x.Value)).ToList();
 94179                var schedulingActivityExecutionId = options?.SchedulingActivityExecutionId;
 94180                var schedulingWorkflowInstanceId = options?.SchedulingWorkflowInstanceId;
 94181                var schedulingCallStackDepth = options?.SchedulingCallStackDepth;
 182
 94183                workflowExecutionContext.ScheduleWorkflow(
 94184                    variables: vars,
 94185                    schedulingActivityExecutionId: schedulingActivityExecutionId,
 94186                    schedulingWorkflowInstanceId: schedulingWorkflowInstanceId,
 94187                    schedulingCallStackDepth: schedulingCallStackDepth);
 188            }
 189        }
 190
 191        // Set variables, if any.
 129192        if (variables != null)
 193        {
 0194            var rootContext = workflowExecutionContext.ActivityExecutionContexts.FirstOrDefault(x => x.ParentActivityExe
 195
 0196            if (rootContext != null)
 197            {
 0198                foreach (var variable in variables)
 0199                    rootContext.SetDynamicVariable(variable.Key, variable.Value);
 200            }
 201        }
 202
 129203        return await RunAsync(workflowExecutionContext);
 129204    }
 205
 206    /// <inheritdoc />
 207    public async Task<RunWorkflowResult> RunAsync(WorkflowExecutionContext workflowExecutionContext)
 208    {
 509209        var loggerState = loggerStateGenerator.GenerateLoggerState(workflowExecutionContext);
 509210        using var loggingScope = logger.BeginScope(loggerState);
 509211        var workflow = workflowExecutionContext.Workflow;
 509212        var cancellationToken = workflowExecutionContext.CancellationToken;
 213
 509214        await notificationSender.SendAsync(new WorkflowExecuting(workflow, workflowExecutionContext), cancellationToken)
 215
 216        // If the status is Pending, it means the workflow is started for the first time.
 509217        var isStarting = workflowExecutionContext.SubStatus == WorkflowSubStatus.Pending;
 509218        if (isStarting)
 219        {
 473220            workflowExecutionContext.TransitionTo(WorkflowSubStatus.Executing);
 473221            await notificationSender.SendAsync(new WorkflowStarted(workflow, workflowExecutionContext), cancellationToke
 222        }
 223
 509224        var telemetryScope = WorkflowInstrumentation.StartWorkflow(workflowExecutionContext, isStarting);
 509225        Exception? workflowExecutionException = null;
 226
 227        try
 228        {
 509229            await pipeline.ExecuteAsync(workflowExecutionContext);
 504230        }
 5231        catch (Exception e)
 232        {
 5233            if (e is not OperationCanceledException)
 2234                workflowExecutionContext.Exception ??= e;
 235
 5236            workflowExecutionException = e;
 5237            throw;
 238        }
 239        finally
 240        {
 509241            WorkflowInstrumentation.StopWorkflow(telemetryScope, workflowExecutionContext, workflowExecutionException);
 242        }
 243
 504244        var workflowState = workflowStateExtractor.Extract(workflowExecutionContext);
 245
 504246        if (workflowState.Status == WorkflowStatus.Finished)
 247        {
 459248            await notificationSender.SendAsync(new WorkflowFinished(workflow, workflowState, workflowExecutionContext), 
 249        }
 250
 504251        var result = workflow.ResultVariable?.Get(workflowExecutionContext.MemoryRegister);
 504252        var workflowExecutionLogEntries = workflowExecutionContext.ExecutionLog.ToList();
 504253        var activityExecutionContexts = workflowExecutionContext.ActivityExecutionContexts.ToList();
 504254        var journal = new Journal(workflowExecutionLogEntries, activityExecutionContexts);
 504255        await notificationSender.SendAsync(new WorkflowExecuted(workflow, workflowState, workflowExecutionContext), canc
 504256        await commitStateHandler.CommitAsync(workflowExecutionContext, workflowState, cancellationToken);
 504257        return new(workflowExecutionContext, workflowState, workflowExecutionContext.Workflow, result, journal);
 504258    }
 259}