< Summary

Information
Class: Elsa.Workflows.Middleware.Activities.DefaultActivityInvokerMiddleware
Assembly: Elsa.Workflows.Core
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Middleware/Activities/DefaultActivityInvokerMiddleware.cs
Line coverage
72%
Covered lines: 44
Uncovered lines: 17
Coverable lines: 61
Total lines: 165
Line coverage: 72.1%
Branch coverage
63%
Covered branches: 24
Total branches: 38
Branch coverage: 63.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
.cctor()100%11100%
InvokeAsync()72.22%231875%
ExecuteActivityAsync()100%22100%
EvaluateInputPropertiesAsync()100%44100%
ShouldCommit(...)35.71%431447.05%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Middleware/Activities/DefaultActivityInvokerMiddleware.cs

#LineLine coverage
 1using System.Reflection;
 2using Elsa.Extensions;
 3using Elsa.Mediator.Contracts;
 4using Elsa.Workflows.Activities;
 5using Elsa.Workflows.CommitStates;
 6using Elsa.Workflows.Pipelines.ActivityExecution;
 7using Microsoft.Extensions.Logging;
 8
 9namespace Elsa.Workflows.Middleware.Activities;
 10
 11/// <summary>
 12/// Provides extension methods to <see cref="IActivityExecutionPipelineBuilder"/>.
 13/// </summary>
 14public static class ActivityInvokerMiddlewareExtensions
 15{
 16    /// <summary>
 17    /// Adds the <see cref="DefaultActivityInvokerMiddleware"/> component to the pipeline.
 18    /// </summary>
 19    public static IActivityExecutionPipelineBuilder UseDefaultActivityInvoker(this IActivityExecutionPipelineBuilder pip
 20}
 21
 22/// <summary>
 23/// A default activity execution middleware component that evaluates the current activity's properties, executes the act
 24/// </summary>
 42125public class DefaultActivityInvokerMiddleware(ActivityMiddlewareDelegate next, ICommitStrategyRegistry commitStrategyReg
 26    : IActivityExecutionMiddleware
 27{
 328    private static readonly MethodInfo ExecuteAsyncMethodInfo = typeof(IActivity).GetMethod(nameof(IActivity.ExecuteAsyn
 29
 30    /// <inheritdoc />
 31    public async ValueTask InvokeAsync(ActivityExecutionContext context)
 32    {
 301933        context.CancellationToken.ThrowIfCancellationRequested();
 34
 301935        var workflowExecutionContext = context.WorkflowExecutionContext;
 36
 37        // Evaluate input properties.
 301938        await EvaluateInputPropertiesAsync(context);
 39
 40        // Prevent the activity from being started if cancellation is requested.
 301941        if (context.CancellationToken.IsCancellationRequested)
 42        {
 043            context.TransitionTo(ActivityStatus.Canceled);
 044            context.AddExecutionLogEntry("Activity cancelled");
 045            return;
 46        }
 47
 48        // Check if the activity can be executed.
 301949        if (!await context.Activity.CanExecuteAsync(context))
 50        {
 051            context.TransitionTo(ActivityStatus.Pending);
 052            context.AddExecutionLogEntry("Precondition Failed", "Cannot execute at this time");
 053            return;
 54        }
 55
 56        // Mark workflow and activity as executing.
 301957        using var executionState = context.EnterExecution();
 58
 59        // Conditionally commit the workflow state.
 301960        if (ShouldCommit(context, ActivityLifetimeEvent.ActivityExecuting))
 061            await context.WorkflowExecutionContext.CommitAsync();
 62
 301963        var previousActivityStatus = context.Status;
 301964        context.TransitionTo(ActivityStatus.Running);
 65
 66        // Execute activity.
 301967        await ExecuteActivityAsync(context);
 68
 300669        var currentActivityStatus = context.Status;
 300670        var activityDidComplete = previousActivityStatus != ActivityStatus.Completed && currentActivityStatus == Activit
 71
 72        // Reset execute delegate.
 300673        workflowExecutionContext.ExecuteDelegate = null;
 74
 75        // If a bookmark was used to resume, burn it if not burnt already by the activity.
 300676        var resumedBookmark = workflowExecutionContext.ResumedBookmarkContext?.Bookmark;
 77
 300678        if (resumedBookmark is { AutoBurn: true })
 79        {
 5580            logger.LogDebug("Auto-burning bookmark {BookmarkId}", resumedBookmark.Id);
 5581            workflowExecutionContext.Bookmarks.Remove(resumedBookmark);
 82        }
 83
 84        // Update execution count.
 300685        context.IncrementExecutionCount();
 86
 87        // Invoke next middleware.
 300688        await next(context);
 89
 90        // If the activity completed, send a notification.
 300691        if (activityDidComplete)
 92        {
 93893            var mediator = context.GetRequiredService<INotificationSender>();
 93894            await mediator.SendAsync(new Notifications.ActivityCompleted(context), context.CancellationToken);
 95        }
 96
 97        // Conditionally commit the workflow state.
 300698        if (ShouldCommit(context, ActivityLifetimeEvent.ActivityExecuted))
 099            await context.WorkflowExecutionContext.CommitAsync();
 3006100    }
 101
 102    /// <summary>
 103    /// Executes the activity using the specified context.
 104    /// This method is virtual so that modules might override this implementation to do things like e.g. asynchronous pr
 105    /// </summary>
 106    protected virtual async ValueTask ExecuteActivityAsync(ActivityExecutionContext context)
 107    {
 3019108        var executeDelegate = context.WorkflowExecutionContext.ExecuteDelegate
 3019109                              ?? (ExecuteActivityDelegate)Delegate.CreateDelegate(typeof(ExecuteActivityDelegate), conte
 110
 3019111        await executeDelegate(context);
 3006112    }
 113
 114    private async Task EvaluateInputPropertiesAsync(ActivityExecutionContext context)
 115    {
 116        // Evaluate containing composite input properties, if any.
 12218117        var compositeContainerContexts = context.GetAncestors().Where(x => x.Activity is Composite).ToList();
 118
 17742119        foreach (var activityExecutionContext in compositeContainerContexts)
 120        {
 5852121            if (!activityExecutionContext.GetHasEvaluatedProperties())
 36122                await activityExecutionContext.EvaluateInputPropertiesAsync();
 123        }
 124
 125        // Evaluate input properties.
 3019126        await context.EvaluateInputPropertiesAsync();
 3019127    }
 128
 129    private bool ShouldCommit(ActivityExecutionContext context, ActivityLifetimeEvent lifetimeEvent)
 130    {
 6025131        var strategyName = context.Activity.GetCommitStrategy();
 6025132        var strategy = string.IsNullOrWhiteSpace(strategyName) ? null : commitStrategyRegistry.FindActivityStrategy(stra
 6025133        var commitAction = CommitAction.Default;
 134
 6025135        if (strategy != null)
 136        {
 0137            var strategyContext = new ActivityCommitStateStrategyContext(context, lifetimeEvent);
 0138            commitAction = strategy.ShouldCommit(strategyContext);
 139        }
 140
 141        switch (commitAction)
 142        {
 143            case CommitAction.Skip:
 0144                return false;
 145            case CommitAction.Commit:
 0146                return true;
 147            case CommitAction.Default:
 148                {
 6025149                    var workflowStrategyName = context.WorkflowExecutionContext.Workflow.Options.CommitStrategyName;
 6025150                    var workflowStrategy = string.IsNullOrWhiteSpace(workflowStrategyName) ? null : commitStrategyRegist
 151
 6025152                    if (workflowStrategy == null)
 6025153                        return false;
 154
 0155                    var workflowLifetimeEvent = lifetimeEvent == ActivityLifetimeEvent.ActivityExecuting ? WorkflowLifet
 0156                    var workflowCommitStateStrategyContext = new WorkflowCommitStateStrategyContext(context.WorkflowExec
 0157                    commitAction = workflowStrategy.ShouldCommit(workflowCommitStateStrategyContext);
 158
 0159                    return commitAction == CommitAction.Commit;
 160                }
 161            default:
 0162                throw new ArgumentOutOfRangeException(nameof(commitAction), commitAction, "Unknown commit action");
 163        }
 164    }
 165}