Up until now, I used Polly's standard CircuitBreaker policy like this:
int retryCount = 2;
PolicyBuilder policyBuilder = Policy
.HandleInner<WebException>()
.Or<WebException>()
.Or<TimeoutException>()
.Or<TimeoutRejectedException>();
AsyncCircuitBreakerPolicy asyncCircuitBreakerPolicy = policyBuilder
.CircuitBreakerAsync(1, TimeSpan.FromSeconds(1), OnBreak, OnReset);
AsyncRetryPolicy asyncWaitAndRetry = policyBuilder
.WaitAndRetryAsync(retryCount, SleepDurationProvider, OnRetry);
AsyncPolicyWrap defaultPolicy = Policy.WrapAsync(
asyncCircuitBreakerPolicy,
asyncWaitAndRetry);
I.e. retry 2 times when an exception is thrown, and after a total of three failures the exception bubbles up to the CircuitBreaker which triggers immediately.
Polly V8 doesn't have this "standard" CircuitBreaker anymore, but something similar to the old "advanced" one. It wants a MinimumThroughput of at least 2, and a failure rate instead of a fixed count. Additionally, it rethrows all Exceptions.
Now I wonder how to migrate to V8. I was thinking about flipping the order of Retry and CircuitBreaker, setting MinimumThroughput = retryCount + 1 and FailureRatio = 1. But then there's also SamplingDuration, so I'd need to make that somehow depend on the expected timeouts, plus the waiting time between retries etc.
Is there another approach to do this? Should I just write my own ResilienceStrategy?
At the time of writing there is an interoperability layer (wrapper) between V8 and V7, but unfortunately it works in one direction only: from V8 to V7 via
.AsAsyncPolicy()and.AsSyncPolicy(). In other words, currently there is no built-in support to wrap your existing V7 policy into a V8 strategy.So, what can we do?
Option #1
Based on your description there are two blockers to use the V8's circuit breaker:
MinimumThroughput's minimal value (2)SamplingDurationGladly whenever you switch the Circuit Breaker to manual control then none of these matter:
FailureRatio,MinimumThroughput,SamplingDurationandBreakDuration.In other words, regardless of their values you can ask the Circuit Breaker to transition into
Isolatedstate or toClosed.Here is a sample code how to do that:
manualControl.SomeExceptionTypeand retry at mostMaxRetriestimes.OnRetrybefore the last attempt we break the circuitClosedafter certain period of time.Here is a sample output:
There are couple of gotchas here:
First, we are moving the Circuit Breaker into an
Isolatedstate before the last attempt, not after. This is because theOnRetryruns before the next retry attempt. One way to solve this problem is to move theOnRetry's logic into the catch blockNow a sample output looks like this:
The second problem and this is the bigger issue: The Circuit Breaker's control code is scattered everywhere. It is hard to encapsulate the current solution into a reusable format.
Option #2
Because your Circuit Breaker should break immediately after the retries have been exhausted that's why you can implement the required CB functionalities by yourself. Here is an example:
Here we basically mimic an atomic boolean flag to capture whether the Circuit breaker is in closed or in open state.
If you run a test like this
then the output will be something like this:
Here the core logic is encapsulated and reusable. With minimal effort the hard coded things can be passed as parameters. Unfortunately this solution is not composable with other resilience strategies.
So, if you want to implement this specific resilience logic then there are many options. If you need to compose it then you have to implement a custom
ResilienceStrategy.