Polly icon indicating copy to clipboard operation
Polly copied to clipboard

Share a circuit between a CircuitBreaker<T>, CircuitBreaker, CircuitBreakerAsync<T> and CircuitBreakerAsync

Open Crown0815 opened this issue 5 years ago • 2 comments

Summary: What are you wanting to achieve?


I would like to define a resilience class which provides the four methods

  • Execute
  • Execute<T>
  • ExecuteAsync
  • Execute<T>

and uses a shared CircuitBreaker. The goal is to be able to use the resilience flexibly but at the same time having a single breaking point independent of which execution mode is used.


What code or approach do you have so far?


So far we have not been using a CircuitBreaker (therefore no shared state) within the individual policies for each Execute implementation. We are currently looking into how to implement it but could not find any solution.

I fount that all CircuitBreaker policies use an ICircuitController<TResult> which could technically be shared between different circuit breakers instances. However since the building process is internal this is not possible (currently).


Crown0815 avatar Apr 21 '20 10:04 Crown0815

Thanks for the suggestion. This is a good idea, and is on the slate for consideration for Polly v8. A potential feature for Polly v8 is to allow users to create custom circuit-breakers, supplying their own ICircuitController. A side benefit is that this would also allow sharing the same ICircuitController instance between two circuit-breaker policy instances - allowing those circuit-breaker policy instances to share state.

(Polly v8 will bring significant benefits in terms of both performance and configuration flexibility, but involves significant recoding, so, for clarity, timescales for that are in the order of months or half-years.)

reisenberger avatar May 02 '20 10:05 reisenberger

Note that with Polly v7, you could use a construct similar to below (using the fact breakers expose their state) to achieve quite a close approximation:

class CombinedCircuitBreaker
{
    // Policies declared here to make a compact example - better dependency-injected, of course.
    private CircuitBreakerPolicy syncBreaker = Policy.Handle<FooException>().CircuitBreaker(/* etc */);
    private AsyncCircuitBreakerPolicy asyncBreaker = Policy.Handle<FooException>().CircuitBreakerAsync(/* etc */);

    public void Execute(Action action)
    {
        if (asyncBreaker.CircuitState == CircuitState.Open || asyncBreaker.CircuitState == CircuitState.Isolated) throw new BrokenCircuitException();

        syncBreaker.Execute(action);
    }

    public T Execute(Func<T> action)
    {
        if (asyncBreaker.CircuitState == CircuitState.Open || asyncBreaker.CircuitState == CircuitState.Isolated) throw new BrokenCircuitException();

        return syncBreaker.Execute(action);
    }

    public async Task ExecuteAsync(Func<Task> action)
    {
        if (syncBreaker.CircuitState == CircuitState.Open || syncBreaker.CircuitState == CircuitState.Isolated) throw new BrokenCircuitException();

        await asyncBreaker.ExecuteAsync(action);
    }

    public async Task<T> ExecuteAsync(Func<Task<T>> action)
    {
        if (syncBreaker.CircuitState == CircuitState.Open || syncBreaker.CircuitState == CircuitState.Isolated) throw new BrokenCircuitException();

        return await asyncBreaker.ExecuteAsync(action);
    }

}

reisenberger avatar May 02 '20 10:05 reisenberger

@Crown0815, this issue is very similar to #959 and will be addressed and closed once v8 is released.

martintmk avatar Apr 25 '23 08:04 martintmk

The alpha is released and you can try it out.

https://www.nuget.org/packages/Polly

Closing the issue.

martintmk avatar Jun 26 '23 11:06 martintmk