Share a circuit between a CircuitBreaker<T>, CircuitBreaker, CircuitBreakerAsync<T> and CircuitBreakerAsync
Summary: What are you wanting to achieve?
I would like to define a resilience class which provides the four methods
ExecuteExecute<T>ExecuteAsyncExecute<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).
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.)
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);
}
}
@Crown0815, this issue is very similar to #959 and will be addressed and closed once v8 is released.
The alpha is released and you can try it out.
https://www.nuget.org/packages/Polly
Closing the issue.