Quick start
Install the NResilience package:
dotnet add package NResilience// One client for the application's lifetime, with the policy already inside it.
private static readonly HttpClient Client = ResilienceHttp.CreateClient();
private static async Task<User?> GetUserAsync(int id, CancellationToken cancellationToken) =>
await Client.GetFromJsonAsync<User>(requestUri: new Uri(uriString: $"https://api.example.com/users/{id}"), cancellationToken: cancellationToken);This creates a working retried client. Provide only your own cancellation token.
CreateClient() uses the Resilience.Http preset, which provides:
- Three attempts
- Exponential backoff with full jitter
- A 30-second deadline
- A 10-second attempt timeout
- An HTTP classifier that retries
503responses but not404responses
The client's handler handles HTTP-specific logic: it rebuilds the request for every attempt, excludes POST requests from the retry path, and scopes the circuit breaker to the host.
Run any call, not just HTTP
Wrap any asynchronous work - such as a queue read, a database call, or a third-party SDK - using RunAsync.
var api = Resilience.Default;
var name = await api.RunAsync(attempt => db.ReadNameAsync(id: id, cancellationToken: attempt), cancellationToken: cancellationToken);The callback provides an attempt token, which differs from the cancellationToken you pass in:
attemptis cancelled when the specific attempt hits itsAttemptTimeout.cancellationTokencancels the entire operation.
Pass the attempt token into your work to ensure that timed-out attempts actually stop.
TIP
Every execution overload requires a callback that takes a CancellationToken. An analyzer in the package notifies you at build time if you pass the wrong token to your work.
Handle outcomes without exceptions
RunAsync throws the exception encountered during the call. To branch on the outcome instead of catching exceptions, use TryRunAsync.
var result = await api.TryRunAsync(attempt => FetchAsync(cancellationToken: attempt), cancellationToken: cancellationToken);
if (!result.TryGetValue(value: out var user))
{
// Why it stopped, and everything that happened on the way.
Console.WriteLine(value: result.StopReason); // AttemptsExhausted
Console.WriteLine(value: result.Attempts); // 2 attempts over 1.2ms: Transient IOException (0.6ms), ...
}Implement your fallback strategy in the if block, such as by serving a cached value or a default.
Next steps
- Key concepts - learn the core terminology and how to organize policies.
- Retry an HTTP call - follow an end-to-end example with the handler.
CallResult<T>- explore the properties of the call outcome.
