< Summary

Information
Class: Elsa.Bpmn.Hosting.BpmnWorkTeardown
Assembly: Elsa.Bpmn
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Bpmn/Hosting/BpmnWorkTeardown.cs
Line coverage
100%
Covered lines: 11
Uncovered lines: 0
Coverable lines: 11
Total lines: 58
Line coverage: 100%
Branch coverage
50%
Covered branches: 2
Total branches: 4
Branch coverage: 50%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
FindContext(...)100%11100%
CancelSubtreeAsync()50%2277.77%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Bpmn/Hosting/BpmnWorkTeardown.cs

#LineLine coverage
 1using Elsa.Extensions;
 2using Elsa.Workflows;
 3
 4namespace Elsa.Bpmn.Hosting;
 5
 6/// <summary>
 7/// Stops a unit of work and everything it in turn started.
 8/// </summary>
 9/// <remarks>
 10/// Both places that tear work down go through here: the interpreter's <c>CancelWorkSubtree</c> command, and a scope
 11/// terminalizing the unit of work whose fault it just claimed. The mechanism is the same in either case, and so is the
 12/// one thing this host cannot do.
 13/// </remarks>
 14internal static class BpmnWorkTeardown
 15{
 16    /// <summary>The activity execution with the given id, or <c>null</c> when it has already gone.</summary>
 17    public static ActivityExecutionContext? FindContext(WorkflowExecutionContext workflowExecutionContext, string activi
 2518        workflowExecutionContext.ActivityExecutionContexts.FirstOrDefault(x => string.Equals(x.Id, activityExecutionCont
 19
 20    /// <summary>
 21    /// Tears down a unit of work and everything underneath it, or refuses when it cannot.
 22    /// </summary>
 23    /// <remarks>
 24    /// <para>
 25    /// Cancellation itself needs no new code: the public <c>CancelActivityAsync</c> extension already walks the child
 26    /// subtree recursively, which is exactly what "and everything it in turn started" means.
 27    /// </para>
 28    /// <para>
 29    /// What it cannot do is withdraw work whose activity is scheduled but has not been invoked yet. Such work has no
 30    /// running execution to cancel, and <c>IActivityScheduler</c> offers no way to remove a queued work item, so the
 31    /// activity runs after BPMN destroyed the branch it belongs to regardless of what this method does. Throwing
 32    /// still fails loudly under <c>FaultStrategy</c>, which is the strategy that justifies it. It does not fail
 33    /// loudly under <c>ContinueWithIncidentsStrategy</c>: there the throw is absorbed into an incident, execution
 34    /// continues, and the stranded activity still runs. What limits the damage in that case is the caller's own
 35    /// doing, not this method's: the caller removes the work's ledger record and persists that removal before
 36    /// invoking this method, so an absorbed throw cannot leave the persisted ledger claiming work that was just torn
 37    /// down, and the stranded activity's eventual completion callback finds no live record and is discarded rather
 38    /// than handed to the interpreter as real work. That does not stop the stray activity from running, and it does
 39    /// not undo whatever side effects it has — it only stops its result from being believed.
 40    /// </para>
 41    /// </remarks>
 42    public static async ValueTask CancelSubtreeAsync(ActivityExecutionContext childContext, string reason)
 43    {
 944        var scheduler = childContext.WorkflowExecutionContext.Scheduler;
 945        var subtree = new[] { childContext }.Concat(childContext.GetDescendants());
 3146        var queued = subtree.FirstOrDefault(context => scheduler.Any(item => item.ExistingActivityExecutionContext?.Id =
 47
 948        if (queued is not null)
 49        {
 350            throw new NotSupportedException(
 351                $"BPMN asked to tear down the work of activity '{childContext.Activity.Id}' ({reason}), but activity "
 352                + $"'{queued.Activity.Id}' inside that subtree is scheduled and has not started, and a scheduled work "
 353                + "item cannot be withdrawn. Running it anyway would leave a branch alive that BPMN destroyed.");
 54        }
 55
 656        await childContext.CancelActivityAsync();
 657    }
 58}