Backoff delay strategies for Polly v8 resilience pipelines.
Polly.Contrib.WaitAndRetry was built for Polly v7's WaitAndRetry() API. Polly v8 uses a DelayGenerator delegate — this package provides the same beloved strategies in the new API.
dotnet add package PollyBackoff
using PollyBackoff;
var pipeline = new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddRetry(new RetryStrategyOptions<HttpResponseMessage>
{
MaxRetryAttempts = 5,
ShouldHandle = new PredicateBuilder<HttpResponseMessage>()
.Handle<HttpRequestException>()
.HandleResult(r => !r.IsSuccessStatusCode)
}
.UseDecorrelatedJitter(baseDelay: TimeSpan.FromMilliseconds(100)))
.Build();var backoff = Backoff.DecorrelatedJitter(baseDelay: TimeSpan.FromMilliseconds(100));
var pipeline = new ResiliencePipelineBuilder()
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 5,
DelayGenerator = args => new ValueTask<TimeSpan?>(backoff(args.AttemptNumber))
})
.Build();Based on the algorithm from Marc Brooker's blog and AWS guidance. Each delay is randomly chosen from [baseDelay, previous × factor], capped at maxDelay. Avoids retry storms by spreading attempts across time.
options.UseDecorrelatedJitter(
baseDelay: TimeSpan.FromMilliseconds(100),
factor: 3.0, // default
maxDelay: TimeSpan.FromSeconds(30)); // defaultdelay = min(maxDelay, baseDelay × factor^attempt), with optional full jitter.
options.UseExponentialBackoff(
baseDelay: TimeSpan.FromMilliseconds(100),
factor: 2.0, // default
maxDelay: TimeSpan.FromSeconds(30),
addJitter: true);delay = baseDelay + increment × attempt, capped at maxDelay.
options.UseLinearBackoff(
baseDelay: TimeSpan.FromMilliseconds(100),
increment: TimeSpan.FromMilliseconds(100), // defaults to baseDelay
maxDelay: TimeSpan.FromSeconds(10),
addJitter: false);Fixed delay every attempt, with optional ±jitter.
options.UseConstantBackoff(
delay: TimeSpan.FromSeconds(1),
addJitter: true,
jitterFactor: 0.1); // ±10%Each strategy also exposes a Func<int, TimeSpan> you can use directly:
var backoff = Backoff.ExponentialBackoff(TimeSpan.FromMilliseconds(100), addJitter: true);
// attempt 0 → ~100ms, attempt 1 → ~200ms, attempt 2 → ~400ms (with jitter)
TimeSpan delay = backoff(attemptNumber);If PollyBackoff saves you time — especially if you're migrating from Polly.Contrib.WaitAndRetry — consider supporting the project:
💼 Need .NET resilience help? Visit solidqualitysolutions.com for consulting and architecture services.
| Package | Description |
|---|---|
| PollyChaos | Chaos engineering — inject faults & latency (Simmy for v8) |
| PollyMediatR | Polly v8 pipelines for MediatR request handlers |
| PollyEFCore | Polly v8 resilience for EF Core queries and SaveChanges |
| PollyHealthChecks | |
| PollyOpenAI | |
| PollyRedis | |
| PollySignalR | |
| PollyGrpc | Polly v8 resilience (retry, CB, timeout) for gRPC .NET clients via Interceptor |
| PollyKafka | Polly v8 resilience (retry, CB, timeout) for Confluent.Kafka producers and consumers |
| PollyAzureEventHub | Polly v8 for Azure Event Hubs |
| PollyAzureServiceBus | Polly v8 resilience (retry, CB, timeout) for Azure Service Bus senders and receivers |
| PollyCaching | Caching resilience strategy |
| PollyBulkhead | Bulkhead isolation |
| PollyRateLimiter | Rate limiting strategies |
| PollyOpenTelemetry | OpenTelemetry metrics & tracing |
| PollyRabbitMQ | Polly v8 resilience for RabbitMQ.Client channels |
| PollyElasticsearch | Polly v8 for Elastic.Clients.Elasticsearch |
| PollyAzureKeyVault | Polly v8 for Azure Key Vault |
| PollySendGrid | Polly v8 for SendGrid |
| PollyMassTransit | Polly v8 for MassTransit |
| PollyAzureTableStorage | Polly v8 for Azure Table Storage |
| PollyMailKit | MailKit SMTP email client | | PollyAzureQueueStorage | Azure Queue Storage QueueClient | | PollyHangfire | Hangfire IBackgroundJobClient |
MIT