Skip to main content
Polly is fast and avoids allocations wherever possible. We use a comprehensive set of performance benchmarks to monitor Polly’s performance. Here’s an example of results from an advanced pipeline composed of the following strategies:
  • Timeout (outer)
  • Rate limiter
  • Retry
  • Circuit breaker
  • Timeout (inner)

Benchmark Results

Compared to older versions, Polly v8 is both faster and more memory efficient.

Performance Tips

If you’re aiming for the best performance with Polly, consider these tips:

Use Static Lambdas

Lambdas capturing variables from their outer scope will allocate on every execution. Polly provides tools to avoid this overhead, as shown in the example below:
Using static lambdas eliminates closure allocations and can significantly improve performance in hot paths.

Use Switch Expressions for Predicates

The PredicateBuilder maintains a list of all registered predicates. To determine whether the results should be processed, it iterates through this list. Using switch expressions can help you bypass this overhead.

Execute Callbacks Without Throwing Exceptions

Polly provides the ExecuteOutcomeAsync API, returning results as Outcome<T>. The Outcome<T> might contain an exception instance, which you can check without it being thrown. This is beneficial when employing exception-heavy resilience strategies, like circuit breakers.
Using ExecuteOutcomeAsync avoids the overhead of exception throwing and catching, which can be significant in high-throughput scenarios.

Reuse Resilience Pipeline Instances

Creating a resilience pipeline can be resource-intensive, so it’s advisable not to discard the instance after each use. Instead, you can either cache the resilience pipeline or use the GetOrAddPipeline(...) method from ResiliencePipelineRegistry<T> to cache the pipeline dynamically:
You can also define your pipeline on startup using dependency injection and then use ResiliencePipelineProvider<T> to retrieve the instance.

Performance Best Practices Summary

Static Lambdas

Use static lambdas and pass state as parameters to avoid closure allocations.

Switch Expressions

Prefer switch expressions over PredicateBuilder for better performance.

Outcome API

Use ExecuteOutcomeAsync to avoid exception throwing overhead.

Reuse Pipelines

Cache and reuse resilience pipeline instances instead of creating new ones.