Polly v8 resilience for Azure.Data.Tables — add retry, timeout, and circuit-breaker to any Table Storage operation in two lines.
var tableClient = new TableClient(connectionString, "orders");
var resilient = tableClient.WithPolly(pipeline => pipeline
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromSeconds(1),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
ShouldHandle = TableStorageTransientErrors.IsTransient,
})
.AddTimeout(TimeSpan.FromSeconds(10)));
await resilient.UpsertEntityAsync(entity);
var response = await resilient.GetEntityAsync<OrderEntity>("partitionKey", "rowKey");Azure Table Storage throttles aggressively at scale and returns 503 during maintenance windows. Without retry logic, a single throttle event causes data loss or visible errors. This library adds Polly v8 resilience with a predicate tuned for Table Storage:
| Problem | Solution |
|---|---|
| HTTP 429 throttling (storage account IOPS limit) | Caught by TableStorageTransientErrors.IsTransient |
| HTTP 503 service unavailable during maintenance | Caught by TableStorageTransientErrors.IsTransient |
| HTTP 504 gateway timeout | Caught by TableStorageTransientErrors.IsTransient |
HttpRequestException network failure |
Caught by TableStorageTransientErrors.IsTransient |
TaskCanceledException timeout in transit |
Caught by TableStorageTransientErrors.IsTransient |
dotnet add package PollyAzureTableStorage
dotnet add package Polly.Core
var client = new TableClient(connectionString, "orders");
var resilient = client.WithPolly(p => p
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromSeconds(1),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
ShouldHandle = TableStorageTransientErrors.IsTransient,
}));
await resilient.UpsertEntityAsync(order);
var result = await resilient.GetEntityAsync<OrderEntity>("Orders", orderId);builder.Services.AddPollyAzureTableStorage(connectionString, "orders", pipeline => pipeline
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromSeconds(1),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
ShouldHandle = TableStorageTransientErrors.IsTransient,
})
.AddTimeout(TimeSpan.FromSeconds(10)));
public class OrderRepository(ResilientTableClient client)
{
public Task UpsertAsync(OrderEntity order, CancellationToken ct)
=> client.UpsertEntityAsync(order, cancellationToken: ct);
public Task<Response<OrderEntity>> GetAsync(string pk, string rk, CancellationToken ct)
=> client.GetEntityAsync<OrderEntity>(pk, rk, cancellationToken: ct);
}| Member | Description |
|---|---|
ResilientTableClient.Inner |
The underlying TableClient |
AddEntityAsync<T>(entity, ct) |
Adds an entity through the pipeline |
UpsertEntityAsync<T>(entity, mode, ct) |
Upserts an entity through the pipeline |
UpdateEntityAsync<T>(entity, ifMatch, mode, ct) |
Updates an entity through the pipeline |
DeleteEntityAsync(pk, rk, ifMatch, ct) |
Deletes an entity through the pipeline |
GetEntityAsync<T>(pk, rk, select?, ct) |
Gets a single entity through the pipeline |
ExecuteAsync<T>(operation, ct) |
Runs any TableClient operation through the pipeline |
TableStorageTransientErrors.IsTransient |
PredicateBuilder for 429/503/504, HttpRequestException, TaskCanceledException |
TableStorageTransientErrors.StatusCodes |
IReadOnlySet<int> — {429, 503, 504} |
client.WithPolly(pipeline) |
Wraps TableClient with a pre-built pipeline |
client.WithPolly(configure) |
Builds pipeline inline and wraps the client |
services.AddPollyAzureTableStorage(configure) |
DI registration (requires TableClient in DI) |
services.AddPollyAzureTableStorage(connStr, table, configure) |
DI with connection string shortcut |
.NET 6 ✅ · .NET 8 ✅ · .NET 9 ✅
| 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 | |
| PollyBackoff | Backoff delay strategies 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 | |
| PollyNpgsql | Polly v8 resilience pipelines for Npgsql (PostgreSQL) — retry, timeout, and circuit-breaker for NpgsqlConnection queries and commands, plus a built-in PostgresTransientErrors predicate covering all common PostgreSQL transient SQLSTATE codes | |
| 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 | |
| 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 | |
| PollyCosmosDb | Polly v8 resilience pipelines for Azure Cosmos DB — retry, timeout, and circuit-breaker for Container operations, plus a built-in CosmosTransientErrors predicate covering rate limiting (429), timeouts (408), partition failovers (410), and service unavailability (503) | |
| PollySendGrid | Polly v8 resilience pipelines for SendGrid — retry, timeout, and circuit-breaker for ISendGridClient.SendEmailAsync | |
| PollyMongo | Polly v8 resilience pipelines for MongoDB.Driver — wrap Find, InsertOne, UpdateOne, DeleteOne and other IMongoCollection calls with retry, timeout, circuit-breaker, and more using a single ResilientMongoCollection decorator | |
| PollyDapper | Polly v8 resilience pipelines for Dapper — wrap QueryAsync, ExecuteAsync, and other Dapper calls with retry, timeout, circuit-breaker, and more using a single ResilientDbConnection decorator | |
| 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 | |
| PollySqlClient | Polly v8 resilience pipelines for Microsoft.Data.SqlClient (SQL Server and Azure SQL) — retry, timeout, and circuit-breaker for SqlConnection queries and commands, plus a built-in SqlServerTransientErrors predicate covering all common SQL Server and Azure SQL transient error numbers | |
| 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 | |
| PollyAzureBlob | Polly v8 resilience pipelines for Azure Blob Storage — wrap BlobClient and BlobContainerClient operations with retry, timeout, circuit-breaker, and more using ResilientBlobClient and ResilientBlobContainerClient decorators | |
| PollyKafka | Polly v8 resilience for Confluent.Kafka — retry, circuit breaker, and timeout for producers and consumers |
The author of this package is available for consulting on Polly v8 resilience, Azure cloud architecture, and clean .NET design.
→ solidqualitysolutions.com · LinkedIn
MIT © Justin Bannister