Skip to content

Some policy patterns

martincostello edited this page Sep 28, 2023 · 13 revisions

Some policy patterns

ℹ️ This documentation describes the previous Polly v7 API. If you are using the new v8 API, please refer to pollydocs.org.

The examples below show some common Policy patterns and address queries which have arisen through github issues. There are however many ways of using Polly - the examples are not intended to be prescriptive!

Patterns on this page apply equally to .Execute(...) and .ExecuteAsync(...) variants

Re-using retry instances

A retry policy instance can safely be used for multiple calls. Each call to .Execute(...) establishes new, independent underlying policy state.

var retryPolicy = Policy.Handle<SomeException>().Retry(3);

// Imagine Foo() encounters exceptions twice but succeeds on the third try ...
retryPolicy.Execute(() => Foo());
 // ... Bar() still gets a full three retries after the initial try.
retryPolicy.Execute(() => Bar());

For example, you might define one retry policy to apply for all calls to a given subsystem:

public class SubsystemGateway()
{
    var retryPolicy = Policy.Handle<HttpRequestException>().Retry(3);

    public SomeResult PlaceCallA()
    {
        return retryPolicy.Execute(() => PlaceCallAInternal());
    }

    public SomeResult PlaceCallB()
    {
        return retryPolicy.Execute(() => PlaceCallBInternal());
    }

    // ...
}

Re-using circuit-breaker instances

A circuit-breaker policy instance can be shared across multiple call sites. This can be used to make all calls break in common if failure in one is likely to mean failure in another - for example they depend on availability of the same underlying subsystem.

In the below example, the shared circuit-breaker means if multiple CallA failures cause the circuit to break, CallB calls can use that knowledge and also fail fast while the circuit is broken.

public class SubsystemGateway()
{
    var breaker = Policy.Handle<HttpRequestException>().CircuitBreaker(5, TimeSpan.FromSeconds(10));

    public SomeResult PlaceCallA()
    {
        return breaker.Execute(() => PlaceCallAInternal());
    }

    public SomeResult PlaceCallB()
    {
        return breaker.Execute(() => PlaceCallBInternal());
    }

    // ...
}

Choose when and when not to share circuit-breaker instances according to the pattern of failure you expect.

Reusing policies and thread-safety

All variants of Polly retry and circuit-breaker policies are thread-safe: in the above examples, multiple threads may safely place calls at the same time.

The internal state of policy instances is thread-safe across calls, but non-thread-safe delegates remain non-thread-safe. In the above examples, if PlaceCallAInternal() and PlaceCallBInternal() share and could corrupt each other's state, they remain non-thread-safe.

Clone this wiki locally