< Summary - AsyncResponse (Release / net8.0+net10.0 / unit+integration)

Information
Class: AsyncResponse.IDurableFlowExecutionObserver
Assembly: AsyncResponse.Abstractions
File(s): /_/src/AsyncResponse.Abstractions/IDurableFlowExecutionObserver.cs
Line coverage
100%
Covered lines: 5
Uncovered lines: 0
Coverable lines: 5
Total lines: 103
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
OnStepStartingAsync(...)100%11100%
OnStepWaitingAsync(...)100%11100%
OnStepCompletedAsync(...)100%11100%
OnRunAttemptFailedAsync(...)100%11100%
OnRunFinishedAsync(...)100%11100%

File(s)

/_/src/AsyncResponse.Abstractions/IDurableFlowExecutionObserver.cs

#LineLine coverage
 1namespace AsyncResponse;
 2
 3/// <summary>What a <see cref="IDurableFlowContext"/> step is.</summary>
 4public enum DurableFlowStepKind
 5{
 6    /// <summary>A local unit of work (<c>StepAsync</c>).</summary>
 7    Local = 0,
 8
 9    /// <summary>A remote operation awaited by correlation id (<c>AwaitStepAsync</c>).</summary>
 10    Awaited = 1,
 11
 12    /// <summary>A durable timer (<c>DelayAsync</c> / <c>DelayUntilAsync</c>).</summary>
 13    Timer = 2,
 14
 15    /// <summary>A child durable flow (<c>AwaitChildFlowAsync</c>).</summary>
 16    ChildFlow = 3
 17}
 18
 19/// <summary>One step-lifecycle observation of a durable-flow execution.</summary>
 20/// <param name="FlowId">The flow run id.</param>
 21/// <param name="StepName">The step's stable name.</param>
 22/// <param name="Kind">What the step is.</param>
 23/// <param name="CorrelationId">
 24/// The awaited step's correlation id (the in-flight breadcrumb), when <paramref name="Kind"/> is
 25/// <see cref="DurableFlowStepKind.Awaited"/>.
 26/// </param>
 27/// <param name="WakeAtUtc">
 28/// The timer step's due time, when <paramref name="Kind"/> is <see cref="DurableFlowStepKind.Timer"/>.
 29/// </param>
 30public readonly record struct DurableFlowStepEvent(
 31    string FlowId,
 32    string StepName,
 33    DurableFlowStepKind Kind,
 34    string? CorrelationId = null,
 35    DateTime? WakeAtUtc = null);
 36
 37/// <summary>A terminal run observation of a durable-flow execution.</summary>
 38/// <param name="FlowId">The flow run id.</param>
 39/// <param name="Status">The terminal status the run reached.</param>
 40/// <param name="Message">The run's last operator-facing message.</param>
 41public readonly record struct DurableFlowRunEvent(
 42    string FlowId,
 43    FlowRunStatus Status,
 44    string? Message);
 45
 46/// <summary>
 47/// Observes durable-flow execution from inside the executor: step activations, waits, checkpoint
 48/// completions, and terminal run transitions. Register implementations in DI (any number, <b>as
 49/// singletons</b> — the singleton flow executor resolves them once from the root provider and
 50/// holds them for its lifetime; a scoped or transient registration fails resolution with an error
 51/// naming this requirement). The flow executor invokes every registered observer synchronously on
 52/// the execution path.
 53/// <para>
 54/// Intended for test instrumentation (AsyncResponse.Testing's harness is built on it) and
 55/// lightweight production telemetry. Because observers run <em>on</em> the execution path, an
 56/// observer that throws fails the current execution attempt exactly like a step failure — the
 57/// delivery retries from the last checkpoint. AsyncResponse.Testing uses precisely that contract
 58/// to inject deterministic crashes at step boundaries; telemetry observers must not throw.
 59/// </para>
 60/// <para>
 61/// All methods have no-op default implementations, so an observer overrides only what it needs.
 62/// </para>
 63/// </summary>
 64public interface IDurableFlowExecutionObserver
 65{
 66    /// <summary>
 67    /// A not-yet-completed step is about to execute its body (local step), trigger or re-attach
 68    /// (awaited step), start or continue its wait (timer), or start/await its child (child-flow
 69    /// step). Memoized (completed) steps are skipped without an event. Fires before the step's
 70    /// first side effect of this execution.
 71    /// </summary>
 193672    ValueTask OnStepStartingAsync(DurableFlowStepEvent step) => default;
 73
 74    /// <summary>
 75    /// The step is now durably parked: an awaited step's trigger completed (or its re-attach began)
 76    /// and the run is waiting on <see cref="DurableFlowStepEvent.CorrelationId"/>; a timer step is
 77    /// waiting for <see cref="DurableFlowStepEvent.WakeAtUtc"/>; a child-flow step is about to
 78    /// suspend this run for its child.
 79    /// </summary>
 480    ValueTask OnStepWaitingAsync(DurableFlowStepEvent step) => default;
 81
 82    /// <summary>The step's completion checkpoint was persisted.</summary>
 283    ValueTask OnStepCompletedAsync(DurableFlowStepEvent step) => default;
 84
 85    /// <summary>
 86    /// The current execution attempt ended without the run reaching a terminal status: the
 87    /// attempt failed (or lost its execution lease) and the delivery retries from the last
 88    /// checkpoint. Any step this attempt had reported waiting is no longer parked in this
 89    /// process; the retry re-raises whatever still applies. Best-effort, unlike the other
 90    /// events: the attempt's own exception is already propagating, so an observer throw here is
 91    /// swallowed rather than allowed to mask it.
 92    /// </summary>
 5293    ValueTask OnRunAttemptFailedAsync(DurableFlowRunEvent run) => default;
 94
 95    /// <summary>
 96    /// The run reached a terminal status (<see cref="FlowRunStatus.Succeeded"/> or
 97    /// <see cref="FlowRunStatus.Failed"/>). Delivered <b>at least once</b> per terminal run: a
 98    /// redelivered duplicate of an already-terminal wake-up re-notifies before acking, because the
 99    /// original notification may be exactly what failed the prior delivery — implementations must
 100    /// tolerate duplicates.
 101    /// </summary>
 6102    ValueTask OnRunFinishedAsync(DurableFlowRunEvent run) => default;
 103}