< Summary

Information
Class: Elsa.Workflows.Runtime.Services.ExecutionCycleRegistry
Assembly: Elsa.Workflows.Runtime
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Runtime/Services/ExecutionCycleRegistry.cs
Line coverage
100%
Covered lines: 21
Uncovered lines: 0
Coverable lines: 21
Total lines: 55
Line coverage: 100%
Branch coverage
100%
Covered branches: 6
Total branches: 6
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_ActiveCount()100%11100%
BeginCycle(...)100%66100%
ListActiveCycles()100%11100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Runtime/Services/ExecutionCycleRegistry.cs

#LineLine coverage
 1using System.Collections.Concurrent;
 2using Elsa.Common;
 3
 4namespace Elsa.Workflows.Runtime.Services;
 5
 6/// <summary>
 7/// Default implementation of <see cref="IExecutionCycleRegistry"/>. Tracks active execution cycles with a
 8/// thread-safe dictionary and detects the FR-018 invariant violation (a source that reports
 9/// <see cref="IngressSourceState.Paused"/> but initiates an execution cycle).
 10/// </summary>
 11public sealed class ExecutionCycleRegistry : IExecutionCycleRegistry
 12{
 18713    private readonly ConcurrentDictionary<Guid, ExecutionCycleHandle> _active = new();
 14    private readonly IIngressSourceRegistry _sources;
 15    private readonly ISystemClock _clock;
 16
 18717    public ExecutionCycleRegistry(IIngressSourceRegistry sources, ISystemClock clock)
 18    {
 18719        _sources = sources;
 18720        _clock = clock;
 18721    }
 22
 23    /// <inheritdoc />
 291824    public int ActiveCount => _active.Count;
 25
 26    /// <inheritdoc />
 27    public ExecutionCycleHandle BeginCycle(string workflowInstanceId, string? ingressSourceName, CancellationToken linke
 28    {
 29        // FR-018: a source that reports Paused but starts an execution cycle is inconsistent — flip it to PauseFailed.
 59030        if (ingressSourceName is not null)
 31        {
 432            var snapshot = _sources.Snapshot().FirstOrDefault(s => s.Name == ingressSourceName);
 233            if (snapshot is not null && snapshot.State == IngressSourceState.Paused)
 34            {
 35                // Fire-and-forget: flipping the recorded state is a local operation that does not await I/O.
 136                _ = _sources.MarkPauseFailedAsync(ingressSourceName, reason: "delivered-while-paused");
 37            }
 38        }
 39
 59040        var handle = new ExecutionCycleHandle(
 59041            id: Guid.NewGuid(),
 59042            workflowInstanceId: workflowInstanceId,
 59043            ingressSourceName: ingressSourceName,
 59044            startedAt: _clock.UtcNow,
 59045            linkedToken: linkedToken,
 57846            onDisposed: h => _active.TryRemove(h.Id, out _),
 59047            cancelCallback: cancelCallback);
 48
 59049        _active[handle.Id] = handle;
 59050        return handle;
 51    }
 52
 53    /// <inheritdoc />
 354    public IReadOnlyCollection<ExecutionCycleHandle> ListActiveCycles() => _active.Values.ToArray();
 55}