Skip to main content
The ResiliencePipeline is the foundation of Polly’s resilience framework. It allows you to execute arbitrary user-provided callbacks while applying one or more resilience strategies to handle transient faults and failures.

What is a Resilience Pipeline?

A resilience pipeline is a combination of one or more resilience strategies that work together to make your application more fault-tolerant. Think of it as a wrapper around your code that adds layers of protection against failures.
A resilience pipeline can contain multiple strategies like retry, circuit breaker, timeout, and rate limiter, all working in harmony to protect your application.

Creating a Resilience Pipeline

You create resilience pipelines using the ResiliencePipelineBuilder. Here’s a simple example:

Executing Code with Pipelines

Once you’ve built a pipeline, you can execute various types of callbacks:
1

Execute asynchronous void callbacks

2

Execute synchronous void callbacks

3

Execute callbacks that return values

4

Execute without lambda allocation (performance optimization)

Dependency Injection Integration

In production applications, you should separate pipeline definition from usage. Polly integrates seamlessly with .NET dependency injection:
Defining pipelines at startup using AddResiliencePipeline is the recommended approach for .NET applications. This makes them easily testable and injectable.

Empty Resilience Pipeline

Polly provides a special empty pipeline that contains no resilience strategies:
The empty pipeline is particularly useful in test scenarios where implementing resilience strategies could slow down test execution or complicate test setup.

Advanced: Retrieving Results with Outcome

For high-performance scenarios, use ExecuteOutcomeAsync to avoid throwing exceptions:
Use ExecuteOutcomeAsync in high-performance scenarios where you need to avoid the overhead of throwing and catching exceptions.

Context vs State

You might wonder about the difference between context and state parameters:

State Object

The state parameter is a performance optimization that allows you to pass data to your callback without using closures. It’s only accessible inside your callback and enables the use of static anonymous methods.

Context Object

The context parameter is accessible throughout the entire pipeline execution, including in strategy delegates like ShouldHandle, OnRetry, and DelayGenerator. Use it to exchange information between different parts of the pipeline.

Rule of Thumb

  • Use state to pass parameters to your decorated method
  • Use context to exchange information between delegates or across retry/hedging attempts

How Strategies Work Together

When you add multiple strategies to a pipeline, they execute in the order you add them, creating layers of protection:

Execution Flow

1

Request enters the pipeline

The caller invokes ExecuteAsync on the pipeline.
2

Outer strategies execute first

The retry strategy (added first) wraps the timeout strategy.
3

Inner strategies execute next

The timeout strategy (added second) wraps your actual code.
4

Your code executes

Your callback runs with all the protection layers active.
5

Strategies handle failures

If a timeout occurs, the timeout strategy throws TimeoutRejectedException, which the retry strategy can catch and retry.

Visualizing Pipeline Execution

Here’s how a retry strategy wrapping a timeout strategy behaves when the first attempt times out but the second succeeds:

Best Practices

Define your pipelines at application startup and inject them where needed. This approach facilitates unit testing and makes your code more maintainable.
The order in which you add strategies affects behavior significantly. Generally:
  • Add timeout around retry to limit total execution time
  • Add retry around timeout to retry individual attempts that time out
  • Add circuit breaker on the outside to fail fast when a service is down
Reuse ResilienceContext instances from the pool to reduce allocations:

Common Pipeline Patterns

Next Steps

Resilience Strategies

Learn about the different types of strategies you can add to pipelines

Resilience Context

Understand how to pass data through pipeline execution