< 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
80%
Covered lines: 97
Uncovered lines: 24
Coverable lines: 121
Total lines: 227
Line coverage: 80.1%
Branch coverage
68%
Covered branches: 41
Total branches: 60
Branch coverage: 68.3%
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%1414100%
RunAsync()100%11100%
RunAsync()100%11100%
RunAsync()50%774474.35%
RunAsync()100%66100%

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 Microsoft.Extensions.Logging;
 11
 12namespace Elsa.Workflows;
 13
 14/// <inheritdoc />
 42015public class WorkflowRunner(
 42016    IServiceProvider serviceProvider,
 42017    IWorkflowExecutionPipeline pipeline,
 42018    IWorkflowStateExtractor workflowStateExtractor,
 42019    IWorkflowBuilderFactory workflowBuilderFactory,
 42020    IWorkflowGraphBuilder workflowGraphBuilder,
 42021    IIdentityGenerator identityGenerator,
 42022    INotificationSender notificationSender,
 42023    ILoggerStateGenerator<WorkflowExecutionContext> loggerStateGenerator,
 42024    ICommitStateHandler commitStateHandler,
 42025    ILogger<WorkflowRunner> logger)
 26    : IWorkflowRunner
 27{
 28    /// <inheritdoc />
 29    public async Task<RunWorkflowResult> RunAsync(IActivity activity, RunWorkflowOptions? options = null, CancellationTo
 30    {
 9931        var workflow = Workflow.FromActivity(activity);
 9932        var workflowGraph = await workflowGraphBuilder.BuildAsync(workflow, cancellationToken);
 9933        return await RunAsync(workflowGraph, options, cancellationToken);
 9934    }
 35
 36    /// <inheritdoc />
 37    public async Task<RunWorkflowResult> RunAsync(IWorkflow workflow, RunWorkflowOptions? options = null, CancellationTo
 38    {
 039        var builder = workflowBuilderFactory.CreateBuilder();
 040        var workflowDefinition = await builder.BuildWorkflowAsync(workflow, cancellationToken);
 041        return await RunAsync(workflowDefinition, options, cancellationToken);
 042    }
 43
 44    /// <inheritdoc />
 45    public async Task<RunWorkflowResult<TResult>> RunAsync<TResult>(WorkflowBase<TResult> workflow, RunWorkflowOptions? 
 46    {
 047        var result = await RunAsync((IWorkflow)workflow, options, cancellationToken);
 048        return new(result.WorkflowExecutionContext, result.WorkflowState, result.Workflow, (TResult)result.Result!, resu
 049    }
 50
 51    /// <inheritdoc />
 52    public async Task<RunWorkflowResult> RunAsync<T>(RunWorkflowOptions? options = null, CancellationToken cancellationT
 53    {
 254        var builder = workflowBuilderFactory.CreateBuilder();
 255        var workflowDefinition = await builder.BuildWorkflowAsync<T>(cancellationToken);
 256        return await RunAsync(workflowDefinition, options, cancellationToken);
 257    }
 58
 59    /// <inheritdoc />
 60    public async Task<TResult> RunAsync<T, TResult>(RunWorkflowOptions? options = null, CancellationToken cancellationTo
 61    {
 062        var builder = workflowBuilderFactory.CreateBuilder();
 063        var workflow = await builder.BuildWorkflowAsync<T>(cancellationToken);
 064        var result = await RunAsync(workflow, options, cancellationToken);
 065        return (TResult)result.Result!;
 066    }
 67
 68    /// <inheritdoc />
 69    public async Task<RunWorkflowResult> RunAsync(WorkflowGraph workflowGraph, RunWorkflowOptions? options = null, Cance
 70    {
 71        // Set up a workflow execution context.
 31572        var instanceId = options?.WorkflowInstanceId ?? identityGenerator.GenerateId();
 31573        var input = options?.Input;
 31574        var properties = options?.Properties;
 31575        var correlationId = options?.CorrelationId;
 31576        var triggerActivityId = options?.TriggerActivityId;
 31577        var parentWorkflowInstanceId = options?.ParentWorkflowInstanceId;
 31578        var workflowExecutionContext = await WorkflowExecutionContext.CreateAsync(
 31579            serviceProvider,
 31580            workflowGraph,
 31581            instanceId,
 31582            correlationId,
 31583            parentWorkflowInstanceId,
 31584            input,
 31585            properties,
 31586            null,
 31587            triggerActivityId,
 31588            cancellationToken);
 89
 90        // Schedule the first activity.
 31591        workflowExecutionContext.ScheduleWorkflow();
 92
 31593        return await RunAsync(workflowExecutionContext);
 31594    }
 95
 96    /// <inheritdoc />
 97    public async Task<RunWorkflowResult> RunAsync(Workflow workflow, RunWorkflowOptions? options = null, CancellationTok
 98    {
 299        var workflowGraph = await workflowGraphBuilder.BuildAsync(workflow, cancellationToken);
 2100        return await RunAsync(workflowGraph, options, cancellationToken);
 2101    }
 102
 103    /// <inheritdoc />
 104    public async Task<RunWorkflowResult> RunAsync(Workflow workflow, WorkflowState workflowState, RunWorkflowOptions? op
 105    {
 2106        var workflowGraph = await workflowGraphBuilder.BuildAsync(workflow, cancellationToken);
 2107        return await RunAsync(workflowGraph, workflowState, options, cancellationToken);
 2108    }
 109
 110    /// <inheritdoc />
 111    public async Task<RunWorkflowResult> RunAsync(WorkflowGraph workflowGraph, WorkflowState workflowState, RunWorkflowO
 112    {
 113        // Create a workflow execution context.
 121114        var input = options?.Input;
 121115        var variables = options?.Variables;
 121116        var properties = options?.Properties;
 121117        var correlationId = options?.CorrelationId ?? workflowState.CorrelationId;
 121118        var triggerActivityId = options?.TriggerActivityId;
 121119        var parentWorkflowInstanceId = options?.ParentWorkflowInstanceId;
 121120        var workflowExecutionContext = await WorkflowExecutionContext.CreateAsync(
 121121            serviceProvider,
 121122            workflowGraph,
 121123            workflowState,
 121124            correlationId,
 121125            parentWorkflowInstanceId,
 121126            input,
 121127            properties,
 121128            null,
 121129            triggerActivityId,
 121130            cancellationToken);
 131
 121132        var bookmarkId = options?.BookmarkId;
 121133        var activityHandle = options?.ActivityHandle;
 134
 121135        if (!string.IsNullOrEmpty(bookmarkId))
 136        {
 72137            var bookmark = workflowState.Bookmarks.FirstOrDefault(x => x.Id == bookmarkId);
 138
 36139            if (bookmark != null)
 36140                workflowExecutionContext.ScheduleBookmark(bookmark);
 141        }
 85142        else if (activityHandle != null)
 143        {
 0144            if (!string.IsNullOrEmpty(activityHandle.ActivityInstanceId))
 145            {
 0146                var activityExecutionContext = workflowExecutionContext.ActivityExecutionContexts.FirstOrDefault(x => x.
 0147                                               ?? throw new("No activity execution context found with the specified ID."
 0148                workflowExecutionContext.ScheduleActivityExecutionContext(activityExecutionContext);
 149            }
 150            else
 151            {
 0152                var activity = workflowExecutionContext.FindActivity(activityHandle);
 0153                if (activity != null) workflowExecutionContext.ScheduleActivity(activity);
 154            }
 155        }
 85156        else if (workflowExecutionContext.Scheduler.HasAny)
 157        {
 158            // Do nothing. The scheduler already has activities to schedule.
 159        }
 160        else
 161        {
 162            // Check if there are any interrupted activities.
 85163            var interruptedActivityExecutionContexts = workflowExecutionContext.ActivityExecutionContexts.Where(x => x.I
 164
 85165            if (interruptedActivityExecutionContexts.Count > 0)
 166            {
 167                // Schedule the interrupted activities.
 0168                foreach (var pendingActivityExecutionContext in interruptedActivityExecutionContexts)
 0169                    workflowExecutionContext.ScheduleActivityExecutionContext(pendingActivityExecutionContext);
 170            }
 171            else
 172            {
 173                // Nothing was scheduled. Schedule the workflow itself.
 85174                var vars = variables?.Select(x => new Variable(x.Key, x.Value)).ToList();
 85175                workflowExecutionContext.ScheduleWorkflow(variables: vars);
 176            }
 177        }
 178
 179        // Set variables, if any.
 121180        if (variables != null)
 181        {
 0182            var rootContext = workflowExecutionContext.ActivityExecutionContexts.FirstOrDefault(x => x.ParentActivityExe
 183
 0184            if (rootContext != null)
 185            {
 0186                foreach (var variable in variables)
 0187                    rootContext.SetDynamicVariable(variable.Key, variable.Value);
 188            }
 189        }
 190
 121191        return await RunAsync(workflowExecutionContext);
 121192    }
 193
 194    /// <inheritdoc />
 195    public async Task<RunWorkflowResult> RunAsync(WorkflowExecutionContext workflowExecutionContext)
 196    {
 436197        var loggerState = loggerStateGenerator.GenerateLoggerState(workflowExecutionContext);
 436198        using var loggingScope = logger.BeginScope(loggerState);
 436199        var workflow = workflowExecutionContext.Workflow;
 436200        var cancellationToken = workflowExecutionContext.CancellationToken;
 201
 436202        await notificationSender.SendAsync(new WorkflowExecuting(workflow, workflowExecutionContext), cancellationToken)
 203
 204        // If the status is Pending, it means the workflow is started for the first time.
 436205        if (workflowExecutionContext.SubStatus == WorkflowSubStatus.Pending)
 206        {
 400207            workflowExecutionContext.TransitionTo(WorkflowSubStatus.Executing);
 400208            await notificationSender.SendAsync(new WorkflowStarted(workflow, workflowExecutionContext), cancellationToke
 209        }
 210
 436211        await pipeline.ExecuteAsync(workflowExecutionContext);
 436212        var workflowState = workflowStateExtractor.Extract(workflowExecutionContext);
 213
 436214        if (workflowState.Status == WorkflowStatus.Finished)
 215        {
 392216            await notificationSender.SendAsync(new WorkflowFinished(workflow, workflowState, workflowExecutionContext), 
 217        }
 218
 436219        var result = workflow.ResultVariable?.Get(workflowExecutionContext.MemoryRegister);
 436220        var workflowExecutionLogEntries = workflowExecutionContext.ExecutionLog.ToList();
 436221        var activityExecutionContexts = workflowExecutionContext.ActivityExecutionContexts.ToList();
 436222        var journal = new Journal(workflowExecutionLogEntries, activityExecutionContexts);
 436223        await notificationSender.SendAsync(new WorkflowExecuted(workflow, workflowState, workflowExecutionContext), canc
 436224        await commitStateHandler.CommitAsync(workflowExecutionContext, workflowState, cancellationToken);
 436225        return new(workflowExecutionContext, workflowState, workflowExecutionContext.Workflow, result, journal);
 436226    }
 227}