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

Information
Class: AsyncResponse.FlowStateUnreadableException
Assembly: AsyncResponse.Abstractions
File(s): /_/src/AsyncResponse.Abstractions/FlowStateUnreadableException.cs
Line coverage
100%
Covered lines: 10
Uncovered lines: 0
Coverable lines: 10
Total lines: 41
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
.ctor(...)100%11100%
get_FlowId()100%11100%
get_Reason()100%11100%

File(s)

/_/src/AsyncResponse.Abstractions/FlowStateUnreadableException.cs

#LineLine coverage
 1namespace AsyncResponse;
 2
 3/// <summary>
 4/// Thrown when a durable-flow ledger row exists but this build cannot interpret it: its JSON is
 5/// malformed, or it carries a schema version outside <see cref="FlowStateSchema.IsReadable"/>.
 6/// <para>
 7/// This is the distinction <see cref="IFlowStateStore.LoadAsync"/> exists to preserve. A
 8/// <c>null</c> load means the run is genuinely gone — never started, already pruned, TTL expired —
 9/// and the only correct response is to acknowledge the wake-up and stop. An unreadable ledger
 10/// means the opposite: the run is still there, still <see cref="FlowRunStatus.Running"/>, and the
 11/// message being handled is very likely its only remaining wake-up. Collapsing the two let a
 12/// replica that could not read a ledger report success and acknowledge that wake-up, stranding a
 13/// live flow with nothing left to resume it.
 14/// </para>
 15/// <para>
 16/// The realistic source is a rolling deployment, which is what the schema gate is for: an older
 17/// replica draws a job whose ledger a newer replica already rewrote. Throwing routes that job into
 18/// the transport's normal retry/dead-letter path, where a replica that <em>can</em> read the
 19/// ledger gets its turn and an operator sees the ones that nothing can.
 20/// </para>
 21/// </summary>
 22public sealed class FlowStateUnreadableException : InvalidOperationException
 23{
 24    /// <summary>Creates the exception for <paramref name="flowId"/>.</summary>
 25    public FlowStateUnreadableException(string flowId, string reason, Exception? innerException = null)
 18326        : base(
 18327            $"Durable flow '{flowId}' has a stored ledger that this build cannot read ({reason}). " +
 18328            "The run still exists and must not be acknowledged as complete; the delivery is retried " +
 18329            "or dead-lettered so a build that can read it, or an operator, resolves it.",
 18330            innerException)
 31    {
 18332        FlowId = flowId;
 18333        Reason = reason;
 18334    }
 35
 36    /// <summary>The flow whose ledger could not be read.</summary>
 8637    public string FlowId { get; }
 38
 39    /// <summary>Why the ledger could not be read, for metrics and operator triage.</summary>
 10840    public string Reason { get; }
 41}