What's the correct way to modify the Duration Break on Polly? I know in the documentation they mention implementing (PolicyRegistry). Is there any example of this? I was implementing Polly CircuitBreaker in one WinService.
-
Add your policy to the policy registry, inject the policy registry, replace the policy in the policy registry (as policies are immutable) and the next time the policy is needed, the new one is used – Ermiya Eskandary Oct 15 '21 at 20:46
-
Could you please elaborate on the dynamic part? Do want to use the 429's `Retry-After` header to set the `durationOfBreak`? Or how do you want to set it? – Peter Csala Oct 16 '21 at 07:23
-
I need change the durationofbreak in real time... ex: first break 1 min, second 1×2 min... etc – Felipe Alves de Lima Oct 16 '21 at 21:27
1 Answers
Circuit Breaker was not designed to use different sleep duration whenever it breaks.
In case of Retry you have the ability to provide a function, called sleepDurationProvider
which is called by the policy to determine the actual sleep duration before issuing the next attempt.
So, in short by design it is not supported. I will show you a workaround, but I do not recommend to use it. I will provide a reasoning after the sample code.
For the sake of simplicity let's have the following method:
static int Probe()
{
Console.WriteLine("Probe has been called");
throw new NotSupportedException();
}
- It prints out the fact that the method has been called then fails immediately.
- IMHO: Not a really useful function :D
Let's define a helper method which increases the time period (>> sleep duration) each and every time whenever it is called:
static IEnumerable<TimeSpan> GetSleepDuration()
{
for (int i = 1; i < 10; i++)
{
yield return TimeSpan.FromSeconds(i);
}
}
- This replaces (more or less) the Retry's
sleepDurationProvider
.
Now it's time to define our Circuit Breaker policy:
var sleepDurationProvider = GetSleepDuration().GetEnumerator();
sleepDurationProvider.MoveNext();
var cb = Policy<int>
.Handle<NotSupportedException>()
.CircuitBreaker(1, TimeSpan.FromSeconds(0),
onBreak: (_, __) => {
Console.WriteLine(sleepDurationProvider.Current.TotalSeconds);
Thread.Sleep((int)sleepDurationProvider.Current.TotalMilliseconds);
sleepDurationProvider.MoveNext();
},
onReset: () => { },
onHalfOpen: () => Console.WriteLine("CB half opens"));
- We get an iterator for the
GetSleepDuration
- We set the successive failure count to 1 so after each
Probe
call the CB will break - We set the
durationOfBreak
to zero because we will wait inside theonBreak
<< the workaround - We print out the sleep duration then we sleep and finally we increase the sleep duration for the next break
In order to ease our testing let's define a retry policy:
var retry = Policy<int>
.Handle<NotSupportedException>()
.WaitAndRetryForever(_ => TimeSpan.FromSeconds(0),
onRetry: (_, __) => Console.WriteLine("Retry is triggered"));
- It handles the
Probe
's exception - It retries forever and waits 0 second between each retry call
Let's wire up the policies and run the test:
Policy.Wrap(retry, cb).Execute(() => Probe());
The output will be:
Probe has been called
1
Retry is triggered
CB half opens
Probe has been called
2
Retry is triggered
CB half opens
Probe has been called
3
Retry is triggered
CB half opens
Probe has been called
4
Retry is triggered
CB half opens
Probe has been called
5
Retry is triggered
CB half opens
Probe has been called
6
Retry is triggered
CB half opens
Probe has been called
7
Retry is triggered
CB half opens
Probe has been called
8
Retry is triggered
CB half opens
Probe has been called
9
Retry is triggered
CB half opens
Probe has been called
9
...
- The
Probe
has been called and failed - CB transits from
Open
toBroken
onBreak
has been called, which block the execution for 1 secondPolicyWrap
escalates the problem to Retry- Retry waits 0 second and issues a new attempt
- CB transits from
Broken
toHal-Open
- The
Probe
has been called and failed - ...
The biggest problem with this solution that it is blocking. Unfortunately there is no async version of onBreak
. (Retry does have onRetryAsync
, in which you could use Task.Delay
instead of Thread.Sleep
)
The second problem is that it relies on the current implementation. This solution won't work if for example the onBreak
is executed on a different thread and the exception is thrown immediately.

- 17,736
- 16
- 35
- 75