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

Information
Class: AsyncResponse.RecoveryCallbackFailedException
Assembly: AsyncResponse.Core
File(s): /_/src/AsyncResponse.Core/RecoveryCallbackFailedException.cs
Line coverage
100%
Covered lines: 9
Uncovered lines: 0
Coverable lines: 9
Total lines: 51
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_Attempts()100%11100%

File(s)

/_/src/AsyncResponse.Core/RecoveryCallbackFailedException.cs

#LineLine coverage
 1namespace AsyncResponse;
 2
 3/// <summary>
 4/// Raised by a publish whose response (or exception) found no live subscriber and whose
 5/// lost-subscriber recovery callbacks could not all be invoked <em>transiently</em>. The message
 6/// was <b>not</b> acknowledged — every registration whose callback did not succeed stays armed,
 7/// and the broker ingress propagates this exception untouched (no <c>SetException</c> escalation,
 8/// which would only re-invoke the same failing callback, or fail flows whose resume merely
 9/// blipped) so the transport redelivers the message under its own bounded policy
 10/// (<c>MaxDeliveryAttempts</c>, then the dead-letter destination). The terminal signal therefore
 11/// survives in the broker until the callback's dependency recovers or an operator replays it from
 12/// the dead-letter queue, instead of being acknowledged into a log line while the flow stays stuck.
 13/// <para>Two paths raise it:</para>
 14/// <list type="bullet">
 15/// <item><description>the <b>failure</b> callback failed on every attempt of its in-process retry
 16/// ladder (<see cref="Attempts"/> is that ladder's length);</description></item>
 17/// <item><description>any resume or exception callback failed transiently, including a single
 18/// registration or a fan-out in which none succeeded (<see cref="Attempts"/> is 1 — transport
 19/// redelivery owns the retry). Successful siblings are deleted; failed registrations stay armed.</description></item>
 20/// </list>
 21/// <para>
 22/// Deterministic callback faults — an unauthorized or unresolvable target, a method that no longer
 23/// binds — are never wrapped in this type. In a partially successful fan-out they are logged
 24/// and retained for watchdog visibility; when every callback fails deterministically, the
 25/// original failure propagates to the ingress's exception-routing policy.
 26/// </para>
 27/// <para>
 28/// A direct caller of <c>IAsyncResponsePublisher.SetResponse</c>/<c>SetException</c> (an HTTP
 29/// callback endpoint, for instance) sees this exception too; answering the remote system with a
 30/// retriable status is the equivalent of the broker's redelivery.
 31/// </para>
 32/// </summary>
 33public sealed class RecoveryCallbackFailedException : Exception
 34{
 35    /// <summary>Creates the exception for <paramref name="correlationId"/> after <paramref name="attempts"/> failed inv
 36    public RecoveryCallbackFailedException(string correlationId, int attempts, Exception innerException)
 5037        : base(
 5038            $"A lost-subscriber recovery callback for correlationId '{correlationId}' failed transiently ({attempts} att
 5039            "the message was not acknowledged so the transport can redeliver it to the registration(s) still armed.",
 5040            innerException)
 41    {
 5042        CorrelationId = correlationId;
 5043        Attempts = attempts;
 5044    }
 45
 46    /// <summary>The correlation id whose recovery callback could not be invoked.</summary>
 3447    public string CorrelationId { get; }
 48
 49    /// <summary>How many in-process invocations were attempted before handing the delivery back to the transport (1 whe
 450    public int Attempts { get; }
 51}