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

Information
Class: AsyncResponse.FlowStateSchema
Assembly: AsyncResponse.Abstractions
File(s): /_/src/AsyncResponse.Abstractions/FlowState.cs
Line coverage
100%
Covered lines: 1
Uncovered lines: 0
Coverable lines: 1
Total lines: 190
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
IsReadable(...)100%11100%

File(s)

/_/src/AsyncResponse.Abstractions/FlowState.cs

#LineLine coverage
 1using System.Text.Json.Serialization;
 2
 3namespace AsyncResponse;
 4
 5/// <summary>Lifecycle of a durable flow run.</summary>
 6public enum FlowRunStatus
 7{
 8    /// <summary>The run is executing or waiting to be (re-)executed.</summary>
 9    Running = 0,
 10
 11    /// <summary>The flow body completed; every step checkpointed as done.</summary>
 12    Succeeded = 1,
 13
 14    /// <summary>
 15    /// The run was terminally failed — by a <see cref="DurableFlowFailedException"/>, or by the
 16    /// lost-subscriber failure route of an awaited step.
 17    /// </summary>
 18    Failed = 2,
 19
 20    /// <summary>
 21    /// The run is parked by an operator. Wake-ups, resumes, and failure signals are ignored
 22    /// while suspended, so a dead-lettered run cannot be resurrected or terminally failed behind
 23    /// the operator's back by a late response. A recovered TERMINAL response is not discarded:
 24    /// it is checkpointed into the suspended run's ledger without waking it, so un-parking
 25    /// replays from that preserved result. Not terminal: set the status back to
 26    /// <see cref="Running"/> and call <c>IDurableFlowExecutor.ResumeAsync</c> to replay the run
 27    /// from its checkpoints. A parent awaiting a suspended child keeps waiting.
 28    /// </summary>
 29    Suspended = 3
 30}
 31
 32/// <summary>
 33/// The persisted state of one durable flow run: which steps completed (with memoized results),
 34/// which awaited step is in flight, and the run's status. This is the flow's entire durable
 35/// memory — the "ledger" of the checkpointed-flow pattern, owned by the library.
 36/// <para>
 37/// <b>Contract warning:</b> instances are serialized into the flow state store and must remain
 38/// readable across deployments. Treat property names as a wire contract — additive changes only;
 39/// <see cref="SchemaVersion"/> lets readers reject entries written with an unrecognized schema
 40/// (see <see cref="FlowStateSchema"/>).
 41/// </para>
 42/// </summary>
 43public sealed class FlowState
 44{
 45    /// <summary>The required wire schema version this state was written with.</summary>
 46    [JsonRequired]
 47    public int SchemaVersion { get; set; } = FlowStateSchema.Current;
 48
 49    /// <summary>
 50    /// Optimistic-concurrency revision maintained by durable flow stores. It starts at zero and is
 51    /// incremented on every conditional checkpoint so a stale executor cannot overwrite newer state.
 52    /// </summary>
 53    public long Revision { get; set; }
 54
 55    /// <summary>The flow run id.</summary>
 56    public string? FlowId { get; set; }
 57
 58    /// <summary>Full name of the flow class, resolved through DI on every (re-)execution.</summary>
 59    public string? FlowTypeName { get; set; }
 60
 61    /// <summary>Full name of the input type.</summary>
 62    public string? InputTypeName { get; set; }
 63
 64    /// <summary>The flow input, serialized as JSON.</summary>
 65    public string? InputJson { get; set; }
 66
 67    /// <summary>The run's lifecycle status.</summary>
 68    public FlowRunStatus Status { get; set; }
 69
 70    /// <summary>The most recent progress or outcome message (operator-facing).</summary>
 71    public string? LastMessage { get; set; }
 72
 73    /// <summary>UTC timestamp the run was created.</summary>
 74    public DateTime? CreatedAtUtc { get; set; }
 75
 76    /// <summary>UTC timestamp of the last persisted change.</summary>
 77    public DateTime? UpdatedAtUtc { get; set; }
 78
 79    /// <summary>How many times the flow body has been entered (start, resumes, redeliveries).</summary>
 80    public int Attempts { get; set; }
 81
 82    /// <summary>Per-step checkpoints, keyed by the step's stable name.</summary>
 83    public Dictionary<string, FlowStepState>? Steps { get; set; }
 84
 85    /// <summary>The flow's user key/value bag (values serialized as JSON).</summary>
 86    public Dictionary<string, string>? Values { get; set; }
 87
 88    /// <summary>Parent flow run id when this run was started by <see cref="IDurableFlowContext.AwaitChildFlowAsync{TFlo
 89    public string? ParentFlowId { get; set; }
 90
 91    /// <summary>Parent step name that is waiting for this child flow, when any.</summary>
 92    public string? ParentStepName { get; set; }
 93
 94    /// <summary>
 95    /// Serialized ambient context captured when the run was started (see
 96    /// <see cref="IAsyncResponseContextPropagator"/>), restored before every (re-)execution —
 97    /// which may happen in a different deployment.
 98    /// </summary>
 99    public Dictionary<string, string>? Context { get; set; }
 100
 101    /// <summary>
 102    /// Retention floor: the earliest UTC instant this ledger may be allowed to expire, stamped when
 103    /// this run — or a descendant flow waiting on this chain — parks for a window longer than the
 104    /// ordinary idle <c>StateExpiry</c>. Every ledger write of a non-terminal run honors it: the
 105    /// TTL a checkpoint stamps is raised to reach this instant, so a concurrent checkpoint that
 106    /// knows nothing about the park (an ancestor's replay, an executor's per-attempt save) cannot
 107    /// shrink the retention back under a wait that is still in progress. Additive wire property:
 108    /// absent on ledgers written before it existed and on runs that never parked beyond their own
 109    /// expiry. Ignored once the run is terminal.
 110    /// </summary>
 111    public DateTime? RetainUntilUtc { get; set; }
 112}
 113
 114/// <summary>One step's checkpoint inside <see cref="FlowState"/>.</summary>
 115public sealed class FlowStepState
 116{
 117    /// <summary>Whether the step completed; completed steps are skipped on re-runs.</summary>
 118    public bool Completed { get; set; }
 119
 120    /// <summary>The step's memoized result (or terminal response payload), serialized as JSON.</summary>
 121    public string? ResultJson { get; set; }
 122
 123    /// <summary>
 124    /// The correlation id of the in-flight awaited operation — the breadcrumb a re-run uses to
 125    /// re-attach instead of re-triggering. Cleared when the step completes.
 126    /// </summary>
 127    public string? PendingCorrelationId { get; set; }
 128
 129    /// <summary>
 130    /// Full name of the awaited step's declared response type, recorded alongside
 131    /// <see cref="PendingCorrelationId"/>. Lost-subscriber recovery serializes its checkpoint AS
 132    /// this type so the wire shape replay deserializes (polymorphic discriminators included) —
 133    /// the recovered payload's runtime type may be a derived type whose runtime-type
 134    /// serialization would not round-trip through the declared type. Cleared when the step
 135    /// completes. Additive: absent on ledgers written before it existed, in which case recovery
 136    /// falls back to the payload's runtime type.
 137    /// </summary>
 138    public string? PendingPayloadTypeFullName { get; set; }
 139
 140    /// <summary>
 141    /// The awaited step's fault deadline — the first arm's instant plus its resolved wait window —
 142    /// persisted alongside <see cref="PendingCorrelationId"/> so a re-attaching execution arms the
 143    /// REMAINDER of the window instead of a fresh full one: the fault clock survives crashes,
 144    /// redeliveries, and lease losses, and a deadline found already elapsed faults the step exactly
 145    /// like a live timeout. Additive wire property: absent on ledgers written before it existed,
 146    /// and for waits whose effective window is unknown — such re-attaches arm the full window
 147    /// again. Stays set after completion as the historical deadline.
 148    /// </summary>
 149    public DateTime? AwaitDeadlineUtc { get; set; }
 150
 151    /// <summary>
 152    /// Whether the last attempt of this step faulted (timeout or exception); a faulted awaited
 153    /// step is restarted fresh instead of re-attached.
 154    /// </summary>
 155    public bool Faulted { get; set; }
 156
 157    /// <summary>The step's most recent message (progress or failure).</summary>
 158    public string? Message { get; set; }
 159
 160    /// <summary>Child flow run id when this checkpoint is waiting for a child flow.</summary>
 161    public string? ChildFlowId { get; set; }
 162
 163    /// <summary>
 164    /// The durable timer's due time when this step is a <c>DelayAsync</c>/<c>DelayUntilAsync</c>
 165    /// timer. Persisted when the timer is first reached, so replays wait out the <em>remainder</em>
 166    /// instead of restarting the delay, and a wake-up delivered early re-parks until this instant.
 167    /// Cleared semantics: stays set after completion as the historical due time. Additive wire
 168    /// property: absent on ledgers written before timers existed.
 169    /// </summary>
 170    public DateTime? WakeAtUtc { get; set; }
 171
 172    /// <summary>UTC timestamp the step completed.</summary>
 173    public DateTime? CompletedAtUtc { get; set; }
 174}
 175
 176/// <summary>
 177/// Wire-schema version stamp for <see cref="FlowState"/>. Readers reject versions not explicitly
 178/// supported by the build instead of guessing compatibility.
 179/// </summary>
 180public static class FlowStateSchema
 181{
 182    /// <summary>The current wire schema version written by this build.</summary>
 183    public const int Current = 1;
 184
 185    /// <summary>
 186    /// Returns <c>true</c> only for a schema version explicitly supported by this build. Add older
 187    /// versions here deliberately if a future release provides a tested migration path.
 188    /// </summary>
 17030189    public static bool IsReadable(int entryVersion) => entryVersion == Current;
 190}

Methods/Properties

IsReadable(System.Int32)