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 | Downloads | Description |
|---|---|---|
| PollyHealthChecks | ASP.NET Core health checks for Polly v8 circuit breakers — expose circuit-breaker state (Closed, HalfOpen, Open, Isolated) as /health endpoint responses | |
| PollyOpenTelemetry | OpenTelemetry instrumentation for Polly v8 resilience pipelines | |
| PollyGrpc | Polly v8 resilience interceptor for gRPC | |
| PollyEFCore | Polly v8 resilience pipelines for Entity Framework Core — wrap every EF Core query and SaveChanges with retry, timeout and circuit-breaker via a single AddPollyResilience() call | |
| PollyRabbitMQ | Polly v8 resilience for RabbitMQ.Client v7+ — retry, circuit-breaker, and timeout for IChannel operations, with built-in RabbitMqTransientErrors predicate covering AlreadyClosedException, BrokerUnreachableException, OperationInterruptedException, and ConnectFailureException | |
| PollyMailKit | Polly v8 resilience pipelines for MailKit — retry, timeout, and circuit-breaker for SmtpClient.SendAsync and any MailKit SMTP operation | |
| PollyMassTransit | Polly v8 resilience pipelines for MassTransit — retry, timeout, and circuit-breaker for IBus.Publish and ISendEndpointProvider.Send | |
| PollyOpenAI | Polly v8 resilience for OpenAI and Azure OpenAI API calls | |
| PollyAzureEventHub | Polly v8 resilience pipelines for Azure Event Hubs — retry, timeout, and circuit-breaker for EventHubProducerClient and EventHubConsumerClient | |
| PollySignalR | Polly v8 reconnect policy for SignalR | |
| PollyElasticsearch | Polly v8 resilience pipelines for Elastic.Clients.Elasticsearch 8+ — retry, timeout, and circuit-breaker for any Elasticsearch operation, plus a built-in ElasticTransientErrors predicate covering rate limiting (429), service unavailability (503), gateway timeouts (504), and connection failures | |
| PollyHangfire | Polly v8 resilience pipelines for Hangfire — retry, timeout, and circuit-breaker for IBackgroundJobClient.Enqueue and Schedule | |
| PollySendGrid | Polly v8 resilience pipelines for SendGrid — retry, timeout, and circuit-breaker for ISendGridClient.SendEmailAsync | |
| PollyMediatR | Polly v8 resilience pipelines for MediatR — add retry, timeout, circuit-breaker, rate-limiting, hedging, and chaos engineering to any MediatR request handler with a single line of DI registration | |
| PollyAzureKeyVault | Polly v8 resilience pipelines for Azure Key Vault — retry, timeout, and circuit-breaker for SecretClient, KeyClient, and CertificateClient | |
| PollyAzureQueueStorage | Polly v8 resilience pipelines for Azure Queue Storage — retry, timeout, and circuit-breaker for Azure.Storage.Queues QueueClient | |
| PollyRedis | Polly v8 resilience for StackExchange.Redis | |
| PollyAzureServiceBus | Polly v8 resilience for Azure Service Bus — retry, circuit breaker, and timeout for sending and receiving messages | |
| PollyKafka | Polly v8 resilience for Confluent.Kafka — retry, circuit breaker, and timeout for producers and consumers | |
| PollyAzureTableStorage | Polly v8 resilience pipelines for Azure Table Storage — retry, timeout, and circuit-breaker for Azure.Data.Tables TableClient | |
| PollyRateLimiter | Convenience extension methods for Polly v8 resilience pipelines: AddFixedWindowRateLimiter, AddSlidingWindowRateLimiter, and AddTokenBucketRateLimiter | |
| PollyCaching | A caching resilience strategy for Polly v8 pipelines | |
| PollyChaos | Chaos engineering and fault-injection resilience strategies for Polly v8 pipelines | |
| PollyBulkhead | Bulkhead isolation strategy for Polly v8 resilience pipelines |
MIT