< 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 />
 50316public class WorkflowRunner(
 50317    IServiceProvider serviceProvider,
 50318    IWorkflowExecutionPipeline pipeline,
 50319    IWorkflowStateExtractor workflowStateExtractor,
 50320    IWorkflowBuilderFactory workflowBuilderFactory,
 50321    IWorkflowGraphBuilder workflowGraphBuilder,
 50322    IIdentityGenerator identityGenerator,
 50323    INotificationSender notificationSender,
 50324    ILoggerStateGenerator<WorkflowExecutionContext> loggerStateGenerator,
 50325    ICommitStateHandler commitStateHandler,
 50326    ILogger<WorkflowRunner> logger)
 27    : IWorkflowRunner
 28{
 29    /// <inheritdoc />
 30    public async Task<RunWorkflowResult> RunAsync(IActivity activity, RunWorkflowOptions? options = null, CancellationTo
 31    {
 11332        var workflow = Workflow.FromActivity(activity);
 11333        var workflowGraph = await workflowGraphBuilder.BuildAsync(workflow, cancellationToken);
 11334        return await RunAsync(workflowGraph, options, cancellationToken);
 11335    }
 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.
 37873        var instanceId = options?.WorkflowInstanceId ?? identityGenerator.GenerateId();
 37874        var input = options?.Input;
 37875        var properties = options?.Properties;
 37876        var correlationId = options?.CorrelationId;
 37877        var triggerActivityId = options?.TriggerActivityId;
 37878        var parentWorkflowInstanceId = options?.ParentWorkflowInstanceId;
 37879        var workflowExecutionContext = await WorkflowExecutionContext.CreateAsync(
 37880            serviceProvider,
 37881            workflowGraph,
 37882            instanceId,
 37883            correlationId,
 37884            parentWorkflowInstanceId,
 37885            input,
 37886            properties,
 37887            null,
 37888            triggerActivityId,
 37889            cancellationToken);
 90
 91        // Schedule the first activity.
 37892        workflowExecutionContext.ScheduleWorkflow(
 37893            schedulingActivityExecutionId: options?.SchedulingActivityExecutionId,
 37894            schedulingWorkflowInstanceId: options?.SchedulingWorkflowInstanceId,
 37895            schedulingCallStackDepth: options?.SchedulingCallStackDepth);
 96
 37897        return await RunAsync(workflowExecutionContext);
 37898    }
 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.
 132118        var input = options?.Input;
 132119        var variables = options?.Variables;
 132120        var properties = options?.Properties;
 132121        var correlationId = options?.CorrelationId ?? workflowState.CorrelationId;
 132122        var triggerActivityId = options?.TriggerActivityId;
 132123        var parentWorkflowInstanceId = options?.ParentWorkflowInstanceId;
 132124        var workflowExecutionContext = await WorkflowExecutionContext.CreateAsync(
 132125            serviceProvider,
 132126            workflowGraph,
 132127            workflowState,
 132128            correlationId,
 132129            parentWorkflowInstanceId,
 132130            input,
 132131            properties,
 132132            null,
 132133            triggerActivityId,
 132134            cancellationToken);
 135
 132136        var bookmarkId = options?.BookmarkId;
 132137        var activityHandle = options?.ActivityHandle;
 138
 132139        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        }
 97146        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        }
 97160        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.
 97167            var interruptedActivityExecutionContexts = workflowExecutionContext.ActivityExecutionContexts.Where(x => x.I
 168
 97169            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.
 97178                var vars = variables?.Select(x => new Variable(x.Key, x.Value)).ToList();
 97179                var schedulingActivityExecutionId = options?.SchedulingActivityExecutionId;
 97180                var schedulingWorkflowInstanceId = options?.SchedulingWorkflowInstanceId;
 97181                var schedulingCallStackDepth = options?.SchedulingCallStackDepth;
 182
 97183                workflowExecutionContext.ScheduleWorkflow(
 97184                    variables: vars,
 97185                    schedulingActivityExecutionId: schedulingActivityExecutionId,
 97186                    schedulingWorkflowInstanceId: schedulingWorkflowInstanceId,
 97187                    schedulingCallStackDepth: schedulingCallStackDepth);
 188            }
 189        }
 190
 191        // Set variables, if any.
 132192        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
 132203        return await RunAsync(workflowExecutionContext);
 132204    }
 205
 206    /// <inheritdoc />
 207    public async Task<RunWorkflowResult> RunAsync(WorkflowExecutionContext workflowExecutionContext)
 208    {
 518209        var loggerState = loggerStateGenerator.GenerateLoggerState(workflowExecutionContext);
 518210        using var loggingScope = logger.BeginScope(loggerState);
 518211        var workflow = workflowExecutionContext.Workflow;
 518212        var cancellationToken = workflowExecutionContext.CancellationToken;
 213
 518214        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.
 518217        var isStarting = workflowExecutionContext.SubStatus == WorkflowSubStatus.Pending;
 518218        if (isStarting)
 219        {
 482220            workflowExecutionContext.TransitionTo(WorkflowSubStatus.Executing);
 482221            await notificationSender.SendAsync(new WorkflowStarted(workflow, workflowExecutionContext), cancellationToke
 222        }
 223
 518224        var telemetryScope = WorkflowInstrumentation.StartWorkflow(workflowExecutionContext, isStarting);
 518225        Exception? workflowExecutionException = null;
 226
 227        try
 228        {
 518229            await pipeline.ExecuteAsync(workflowExecutionContext);
 513230        }
 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        {
 518241            WorkflowInstrumentation.StopWorkflow(telemetryScope, workflowExecutionContext, workflowExecutionException);
 242        }
 243
 513244        var workflowState = workflowStateExtractor.Extract(workflowExecutionContext);
 245
 513246        if (workflowState.Status == WorkflowStatus.Finished)
 247        {
 468248            await notificationSender.SendAsync(new WorkflowFinished(workflow, workflowState, workflowExecutionContext), 
 249        }
 250
 513251        var result = workflow.ResultVariable?.Get(workflowExecutionContext.MemoryRegister);
 513252        var workflowExecutionLogEntries = workflowExecutionContext.ExecutionLog.ToList();
 513253        var activityExecutionContexts = workflowExecutionContext.ActivityExecutionContexts.ToList();
 513254        var journal = new Journal(workflowExecutionLogEntries, activityExecutionContexts);
 513255        await notificationSender.SendAsync(new WorkflowExecuted(workflow, workflowState, workflowExecutionContext), canc
 513256        await commitStateHandler.CommitAsync(workflowExecutionContext, workflowState, cancellationToken);
 513257        return new(workflowExecutionContext, workflowState, workflowExecutionContext.Workflow, result, journal);
 513258    }
 259}