PollyNpgsql 1.0.0
dotnet add package PollyNpgsql --version 1.0.0
NuGet\Install-Package PollyNpgsql -Version 1.0.0
<PackageReference Include="PollyNpgsql" Version="1.0.0" />
<PackageVersion Include="PollyNpgsql" Version="1.0.0" />
<PackageReference Include="PollyNpgsql" />
paket add PollyNpgsql --version 1.0.0
#r "nuget: PollyNpgsql, 1.0.0"
#:package PollyNpgsql@1.0.0
#addin nuget:?package=PollyNpgsql&version=1.0.0
#tool nuget:?package=PollyNpgsql&version=1.0.0
PollyNpgsql
Polly v8 resilience 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. Zero changes to your existing SQL.
// One line of setup
var resilient = connection.WithPolly(pipeline =>
pipeline
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
ShouldHandle = PostgresTransientErrors.IsTransient, // built-in ✔
})
.AddTimeout(TimeSpan.FromSeconds(10)));
// Use exactly like NpgsqlConnection
var orders = await resilient.QueryAsync(
"SELECT id, total FROM orders WHERE customer_id = $1",
r => new Order(r.GetInt32(0), r.GetDecimal(1)),
parameters: [new NpgsqlParameter { Value = customerId }]);
Installation
dotnet add package PollyNpgsql
Targets net6.0, net8.0, and net9.0.
Dependencies: Polly.Core 8.*, Npgsql 9.*, Microsoft.Extensions.DependencyInjection.Abstractions 8.*
PostgresTransientErrors — the key feature
Knowing which PostgreSQL errors are safe to retry is the hard part. PollyNpgsql ships a pre-built PostgresTransientErrors.IsTransient predicate so you don't have to look up SQLSTATE codes.
new RetryStrategyOptions
{
MaxRetryAttempts = 3,
ShouldHandle = PostgresTransientErrors.IsTransient,
}
| SQLSTATE | Name | When it occurs |
|---|---|---|
40001 |
serialization_failure |
Concurrent transaction conflict |
40P01 |
deadlock_detected |
Two transactions blocking each other |
53300 |
too_many_connections |
Connection pool exhausted |
53400 |
configuration_limit_exceeded |
Resource limit hit |
57P03 |
cannot_connect_now |
Server starting up or shutting down |
08000 |
connection_exception |
General connection error |
08006 |
connection_failure |
Connection dropped mid-query |
08001 |
sqlclient_unable_to_establish_sqlconnection |
Cannot reach server |
08004 |
sqlserver_rejected_establishment_of_sqlconnection |
Server rejected connection |
The raw set is also available if you need to extend it:
// Add custom codes
var myStates = PostgresTransientErrors.SqlStates.ToHashSet();
myStates.Add("57014"); // query_canceled (e.g. statement_timeout)
new RetryStrategyOptions
{
ShouldHandle = new PredicateBuilder().Handle<NpgsqlException>(ex =>
ex is PostgresException pg && myStates.Contains(pg.SqlState))
}
Quick start
Inline pipeline
using PollyNpgsql;
await using var connection = new NpgsqlConnection(connectionString);
var resilient = connection.WithPolly(pipeline =>
pipeline
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromMilliseconds(200),
BackoffType = DelayBackoffType.Exponential,
ShouldHandle = PostgresTransientErrors.IsTransient,
})
.AddTimeout(TimeSpan.FromSeconds(30)));
await resilient.OpenAsync();
// Execute non-query
await resilient.ExecuteAsync(
"INSERT INTO events (type, payload) VALUES ($1, $2)",
parameters: [new("type") { Value = "OrderPlaced" }, new("payload") { Value = json }]);
// Query with mapper
var orders = await resilient.QueryAsync(
"SELECT id, total FROM orders WHERE customer_id = $1",
reader => new Order(reader.GetInt32(0), reader.GetDecimal(1)),
parameters: [new NpgsqlParameter { Value = customerId }]);
// Scalar
var count = await resilient.ExecuteScalarAsync<long>("SELECT COUNT(*) FROM orders");
Dependency injection
// Program.cs
builder.Services.AddScoped(_ => new NpgsqlConnection(connectionString));
builder.Services.AddPollyNpgsql(pipeline =>
pipeline
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromMilliseconds(200),
BackoffType = DelayBackoffType.Exponential,
ShouldHandle = PostgresTransientErrors.IsTransient,
})
.AddTimeout(TimeSpan.FromSeconds(30))
.AddCircuitBreaker(new CircuitBreakerStrategyOptions
{
FailureRatio = 0.5,
MinimumThroughput = 10,
SamplingDuration = TimeSpan.FromSeconds(30),
BreakDuration = TimeSpan.FromSeconds(15),
}));
// Repository
public class OrderRepository(NpgsqlConnection db, ResiliencePipeline pipeline)
{
public async Task<List<Order>> GetByCustomerAsync(int customerId)
{
var resilient = db.WithPolly(pipeline);
await resilient.OpenAsync();
return await resilient.QueryAsync(
"SELECT id, total FROM orders WHERE customer_id = $1",
r => new Order(r.GetInt32(0), r.GetDecimal(1)),
parameters: [new NpgsqlParameter { Value = customerId }]);
}
}
Supported operations
| Method | Description |
|---|---|
OpenAsync |
Open the connection with retry |
ExecuteAsync |
Execute non-query, returns rows affected |
ExecuteScalarAsync<T> |
Execute scalar, returns first column of first row |
QueryAsync<T> |
Query with row mapper, returns List<T> |
QueryFirstOrDefaultAsync<T> |
Query with row mapper, returns first row or default |
Pipeline order
[Timeout] → [Retry] → [Circuit Breaker] → [Npgsql]
pipeline
.AddTimeout(TimeSpan.FromSeconds(30)) // 1. Overall deadline
.AddRetry(retryOptions) // 2. Retry transient failures
.AddCircuitBreaker(cbOptions) // 3. Open circuit under load
Related packages
| Package | Downloads | Description |
|---|---|---|
| PollyDapper | Polly v8 resilience for Dapper (works with any IDbConnection including Npgsql) | |
| PollyEFCore | Polly v8 resilience for EF Core queries and SaveChanges | |
| PollyMongo | Polly v8 resilience for MongoDB.Driver | |
| PollyAzureBlob | Polly v8 resilience for Azure Blob Storage | |
| PollyRedis | Polly v8 resilience for StackExchange.Redis | |
| PollyMediatR | Polly v8 resilience pipelines for MediatR | |
| PollyAzureServiceBus | Polly v8 resilience for Azure Service Bus | |
| PollyHealthChecks | ASP.NET Core health checks for Polly v8 circuit breakers | |
| PollyBackoff | Jitter, linear & custom backoff for Polly v8 retry |
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net6.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Npgsql (>= 9.0.5)
- Polly.Core (>= 8.7.0)
-
net8.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Npgsql (>= 9.0.5)
- Polly.Core (>= 8.7.0)
-
net9.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Npgsql (>= 9.0.5)
- Polly.Core (>= 8.7.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 51 | 6/24/2026 |
1.0.0: Initial release. ResilientNpgsqlConnection wraps Npgsql queries and commands in a Polly v8 ResiliencePipeline. Includes PostgresTransientErrors helper with pre-built ShouldHandle predicate. Supports net6.0, net8.0, and net9.0.