CallResult<T>
CallResult<T> is a readonly struct returned by the TryRunAsync overloads. It carries the outcome of a resilience operation and the attempt history.
| Member | Description |
|---|---|
IsSuccess | true if an attempt returned a value that the classifier identified as Ok. This is the test a fallback branches on. |
Value | The value returned by the final attempt, or default if every attempt threw an exception. This is populated even on failure - for example, a final 503 Service Unavailable response is returned so the caller can dispose of it. |
ReturnedValue | true if an attempt got as far as returning something, so Value holds what it returned. Not the same question as IsSuccess: when the last attempt returned a value the classifier refused, this is true and IsSuccess is false. Branch on IsSuccess to decide whether to serve the value; branch on this one to decide whether there is something to dispose. |
Exception | The exception thrown by the last attempt, or a library-specific exception (such as a deadline timeout). |
Reason | The StopReason the execution loop stopped for. |
Attempts | The log of all attempts made during the call. |
TryGetValue(out T value) | true if the call succeeded. This is the recommended method for most call sites to check for success. |
ValueOrThrow() | Returns the value if the call succeeded, otherwise rethrows the failure exception with its original stack trace intact. |
ThrowIfFailed() | Rethrows the failure exception, with its original stack trace intact, if there was one. Use it when you want the exception but not the value. |
CallResult (the non-generic version) provides the same members without the four about a value: Value, ReturnedValue, TryGetValue, and ValueOrThrow.
Note: TryRunAsync still throws an exception if the caller's CancellationToken is cancelled.
CallResult<IAsyncEnumerable<T>> - what the streaming TryRunAsync returns - is the one shape with a rule of its own. Its Value is an enumeration the policy has already started, so ReturnedValue is never true on a failure, and a successful value is enumerable once and implements IAsyncDisposable: enumerate it, or dispose it when you decide not to.
Example: implement a fallback
Use the result to serve a fallback value when a call fails:
private async Task<User> ReadUserAsync(UserCache cache, CancellationToken cancellationToken)
{
var result = await Resilience.Http.TryRunAsync(attempt => FetchAsync(cancellationToken: attempt), cancellationToken: cancellationToken);
if (result.TryGetValue(value: out var user))
return user;
_logger.LogWarning(message: "Serving the cached user: {Reason} after {Attempts}", result.Reason, result.Attempts);
return cache.LastKnownGood;
}StopReason
The StopReason enum, carried on Reason, says why the resilience loop stopped.
| Value | Meaning |
|---|---|
Succeeded | An attempt returned a result that the classifier identified as Ok. |
Permanent | The outcome was classified as Permanent, so the handler did not retry. |
AttemptsExhausted | The maximum number of attempts allowed by the policy was reached. |
DeadlineExceeded | The overall wall-clock budget for the call expired. |
BudgetExhausted | The retry budget refused to fund another attempt. |
DependencyUnavailable | A circuit breaker refused to execute the call. |
Draining | The process is shutting down, so the call stopped with the failure it had rather than starting another attempt. The failure is the dependency's own, not a CallRejectedException - see Drain-aware shutdown. |
AttemptLog
AttemptLog is a sealed class that implements IReadOnlyList<Attempt>.
| Member | Description |
|---|---|
Count | The number of attempts executed. |
Elapsed | The wall-clock time from the start of the call until the final attempt returned. |
this[int index] | The attempt at the specified 0-based index. |
AttemptLog.Empty | A static instance of an empty log. |
AttemptLog.Of(Exception) | Extracts the log attached to an exception that the library rethrew. |
AttemptLog.DataKey | The Exception.Data key used to store the log: "NResilience.Attempts". |
ToString() | Returns a human-readable summary of the attempts and delays. |
TryRunAsync always materializes the log; RunAsync materializes it only when a call is about to fail.
Attempt
Attempt is a readonly struct representing a single completed attempt.
| Member | Description |
|---|---|
Number | The 1-based index of the attempt. |
Duration | The time taken for the callback to execute. |
DelayBefore | The backoff delay served immediately before this attempt (zero for the first attempt). |
Verdict | The classification of the outcome. The kind is recorded; RetryAfter is not, because it is observable as the next attempt's DelayBefore. |
Exception | The exception thrown by this attempt, or null if it returned a value. |
Remaining | The time remaining on the deadline when the attempt started. |
StartOffset | When the attempt started, measured from the start of the call. Two entries whose ranges overlap ran at the same time. |
IsHedged | Whether this attempt was started as a copy of one that had not come back yet. |
IsDiscarded | Whether this attempt was cancelled because a sibling answered first. Such an attempt was never classified, so its Verdict carries no information. |
