Introduction
For years, Polly was the go-to library for building resilient .NET applications. Retry policies, circuit breakers, timeouts—everything lived in Polly.
Starting with .NET 8, Microsoft introduced built-in Resilience Pipelines, marking a major shift in how fault tolerance is implemented in ASP.NET Core.
This article explores:
What resilience pipelines are
How they differ from Polly
How to build retry, timeout, and circuit breaker pipelines
Real-world API examples
Best practices for production systems
Why Resilience Matters in Distributed Systems
In modern systems:
Without resilience:
One failure cascades
Threads block
APIs crash under load
Resilience pipelines solve this inside the framework, not via third-party middleware.
What Are Resilience Pipelines?
A Resilience Pipeline is a composable execution flow that applies fault-handling strategies such as:
Retry
Timeout
Circuit Breaker
Hedging
Rate Limiting
They are:
Built on System.Threading.RateLimiting
Fully async
Dependency-injection friendly
Designed for cloud-native workloads
Adding Resilience Support
Required Package
dotnet add package Microsoft.Extensions.Resilience
Configuring a Resilience Pipeline
Step 1: Register Pipelines in Program.cs
using Microsoft.Extensions.Resilience;
using Polly.Timeout;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddResiliencePipeline("external-api", pipeline =>
{
pipeline
.AddTimeout(TimeSpan.FromSeconds(3))
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromMilliseconds(500),
BackoffType = DelayBackoffType.Exponential
})
.AddCircuitBreaker(new CircuitBreakerStrategyOptions
{
FailureRatio = 0.5,
SamplingDuration = TimeSpan.FromSeconds(30),
MinimumThroughput = 10,
BreakDuration = TimeSpan.FromSeconds(15)
});
});
builder.Services.AddHttpClient<WeatherClient>()
.AddResilienceHandler("external-api");
var app = builder.Build();
app.MapControllers();
app.Run();
What’s Happening Here?
| Strategy | Purpose |
|---|
| Timeout | Prevents thread starvation |
| Retry | Handles transient failures |
| Circuit Breaker | Stops cascading failures |
Unlike Polly, this pipeline is
Centralized
Declarative
Observable
Using Resilience in a Typed HTTP Client
Step 2: Create a Typed Client
public class WeatherClient
{
private readonly HttpClient _httpClient;
public WeatherClient(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<string> GetWeatherAsync()
{
var response = await _httpClient.GetAsync("https://external-api/weather");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
Failures here will automatically:
Exposing the API Endpoint
[ApiController]
[Route("api/weather")]
public class WeatherController : ControllerBase
{
private readonly WeatherClient _client;
public WeatherController(WeatherClient client)
{
_client = client;
}
[HttpGet]
public async Task<IActionResult> Get()
{
var result = await _client.GetWeatherAsync();
return Ok(result);
}
}
Advanced: Using Hedging for Faster Responses
Hedging sends multiple parallel requests and uses the fastest response.
pipeline.AddHedging(new HedgingStrategyOptions
{
MaxHedgedAttempts = 2,
Delay = TimeSpan.FromMilliseconds(200)
});
This is ideal for:
High-latency APIs
Read-heavy services
Geo-distributed systems
Observability and Metrics
Resilience pipelines integrate with:
OpenTelemetry
ILogger
Metrics providers
Example:
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics.AddAspNetCoreInstrumentation();
metrics.AddHttpClientInstrumentation();
});
You get visibility into:
Retry counts
Circuit breaker states
Timeout failures
When to Use Resilience Pipelines vs Polly?
| Scenario | Recommendation |
|---|
| New .NET 8+ apps | Resilience Pipelines |
| Legacy systems | Polly |
| Deep customization | Polly |
| Cloud-native APIs | Resilience Pipelines |
Production Best Practices
✔ Avoid retries on non-idempotent requests
✔ Keep timeouts short
✔ Monitor circuit breaker states
✔ Combine with rate limiting
✔ Test failure scenarios locally
Why This Matters for .NET Developers
Resilience Pipelines represent:
Microsoft’s future direction
A move away from external dependencies
A standardized approach to fault tolerance
Ignoring this feature means missing one of the most important architectural improvements in modern .NET.
Conclusion
With .NET 8, resilience is no longer an afterthought or a third-party concern. Resilience pipelines offer a powerful, built-in, and production-ready way to build fault-tolerant ASP.NET Core applications.
If you’re building APIs for real-world traffic, this feature is no longer optional—it’s essential.