Skip to content

Some policy patterns

reisenberger edited this page Dec 10, 2015 · 14 revisions

There are many ways of using Polly. The examples below show common patterns and address queries which have been raised in github issues.

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.

Async variants

The information on this page applies equally to .Execute(...) and .ExecuteAsync(...) variants.

Clone this wiki locally