Skip to content

Some policy patterns

reisenberger edited this page May 11, 2016 · 13 revisions

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());

More generalised:

public class SubsystemGateway()
{
    var retryPolicy = Policy.Handle<HttpException>().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 calls. 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<HttpException>().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.

Nesting policies

Calls through policies may be nested:

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

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

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

    // ...
}

Thread-safety

Calls to .Execute() are thread-safe for both retry policy instances and circuit-breaker instances.

In the above examples, multiple threads may safely place calls at the same time.

The internal state of policy instances is thread-safe, 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