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

Information
Class: AsyncResponse.RecoveryStateUnreadableException
Assembly: AsyncResponse.Abstractions
File(s): /_/src/AsyncResponse.Abstractions/RecoveryStateUnreadableException.cs
Line coverage
100%
Covered lines: 10
Uncovered lines: 0
Coverable lines: 10
Total lines: 48
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_CorrelationId()100%11100%
get_UnreadableCount()100%11100%

File(s)

/_/src/AsyncResponse.Abstractions/RecoveryStateUnreadableException.cs

#LineLine coverage
 1namespace AsyncResponse;
 2
 3/// <summary>
 4/// Thrown by <see cref="IRecoveryStateStore.GetAllAsync"/> when a correlation id has stored
 5/// recovery registrations but this build cannot interpret <em>any</em> of them: malformed JSON, an
 6/// incomplete identity, or a schema version outside
 7/// <see cref="RecoveryStateSchema.IsReadable"/>. Stores whose registrations share one blob per
 8/// correlation id (Redis, NATS) also throw it from <see cref="IRecoveryStateStore.SaveAsync"/>
 9/// when the stored envelope itself is unparseable: a rewrite that read "unreadable" as "missing"
 10/// would commit just the new registration over registrations it could not enumerate, destroying
 11/// every armed callback the blob held.
 12/// <para>
 13/// The same distinction <see cref="FlowStateUnreadableException"/> draws for durable-flow ledgers,
 14/// applied to the recovery path. An empty registration list means "nobody ever armed a recovery
 15/// callback for this response", and the lost-subscriber dispatcher answers that by acknowledging
 16/// the delivery — correctly, because there is nothing to run. Filtering unreadable rows down to an
 17/// empty list made a corrupt or newer-schema registration indistinguishable from that, so a
 18/// terminal response was acknowledged while the callback that should have received it never ran and
 19/// the response ceased to exist.
 20/// </para>
 21/// <para>
 22/// <b>Only the all-unreadable case throws.</b> When at least one registration is readable, those
 23/// are dispatched and the unreadable remainder is logged and counted instead: failing a mixed batch
 24/// would redeliver callbacks that already succeeded, and — since successful registrations are
 25/// deleted — the redelivery would find only the unreadable rows and fail again, turning a partially
 26/// corrupt record into a permanent redelivery loop.
 27/// </para>
 28/// </summary>
 29public sealed class RecoveryStateUnreadableException : InvalidOperationException
 30{
 31    /// <summary>Creates the exception for <paramref name="correlationId"/>.</summary>
 32    public RecoveryStateUnreadableException(string? correlationId, int unreadableCount)
 1833        : base(
 1834            $"All {unreadableCount} stored recovery registration(s) for correlation id '{correlationId}' are unreadable 
 1835            "this build (malformed, incomplete identity, or an unsupported schema version). The response must not be " +
 1836            "acknowledged as handled; the delivery is retried or dead-lettered so a build that can read them, or an " +
 1837            "operator, resolves it.")
 38    {
 1839        CorrelationId = correlationId;
 1840        UnreadableCount = unreadableCount;
 1841    }
 42
 43    /// <summary>The correlation id whose registrations could not be read.</summary>
 844    public string? CorrelationId { get; }
 45
 46    /// <summary>How many stored registrations were rejected, for metrics and operator triage.</summary>
 447    public int UnreadableCount { get; }
 48}