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:

Why Resilience Matters in Distributed Systems

In modern systems:

Without resilience:

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:

They are:

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?

StrategyPurpose
TimeoutPrevents thread starvation
RetryHandles transient failures
Circuit BreakerStops cascading failures

Unlike Polly, this pipeline is

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:

Observability and Metrics

Resilience pipelines integrate with:

Example:

builder.Services.AddOpenTelemetry()
    .WithMetrics(metrics =>
    {
        metrics.AddAspNetCoreInstrumentation();
        metrics.AddHttpClientInstrumentation();
    });

You get visibility into:

When to Use Resilience Pipelines vs Polly?

ScenarioRecommendation
New .NET 8+ appsResilience Pipelines
Legacy systemsPolly
Deep customizationPolly
Cloud-native APIsResilience 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:

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.