Polly CircuitBreaker - 动态中断持续时间
Polly CircuitBreaker - Dynamic Duration of Break
在 Polly 上修改 Duration Break 的正确方法是什么?
我知道他们在文档中提到实施(PolicyRegistry)。
有这方面的例子吗?
我在一个 WinService 中实现了 Polly CircuitBreaker。
断路器未设计为在断开时使用不同的睡眠持续时间。
In case of Retry you have the ability to provide a function,称为 sleepDurationProvider
,由策略调用以确定发出下一次尝试之前的实际睡眠持续时间。
所以,简而言之 by design it is not supported。我将向您展示一种解决方法,但我不 推荐使用它。我会在示例代码后给出推理。
为了简单起见,我们采用以下方法:
static int Probe()
{
Console.WriteLine("Probe has been called");
throw new NotSupportedException();
}
- 它打印出该方法已被调用的事实,然后立即失败。
- 恕我直言:不是一个真正有用的功能 :D
让我们定义一个辅助方法,每次调用时都会增加时间段(>> 睡眠持续时间):
static IEnumerable<TimeSpan> GetSleepDuration()
{
for (int i = 1; i < 10; i++)
{
yield return TimeSpan.FromSeconds(i);
}
}
- 这(或多或少)取代了 Retry 的
sleepDurationProvider
。
现在是时候定义我们的断路器策略了:
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"));
- 我们得到了
GetSleepDuration
的迭代器
- 我们将连续失败计数设置为 1,因此在每次
Probe
调用后 CB 都会中断
- 我们将
durationOfBreak
设置为零,因为我们将在 onBreak
<< 解决方法 中等待
- 我们打印出睡眠持续时间然后我们睡觉,最后我们增加下一次休息的睡眠持续时间
为了简化我们的测试,让我们定义一个重试策略:
var retry = Policy<int>
.Handle<NotSupportedException>()
.WaitAndRetryForever(_ => TimeSpan.FromSeconds(0),
onRetry: (_, __) => Console.WriteLine("Retry is triggered"));
- 它处理
Probe
的异常
- 它永远重试并在每次重试调用之间等待 0 秒
让我们连接策略和 运行 测试:
Policy.Wrap(retry, cb).Execute(() => Probe());
输出将是:
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
...
Probe
已调用但失败
- CB 从
Open
过渡到 Broken
onBreak
被调用,阻塞执行1秒
PolicyWrap
将问题升级为重试
- 重试等待 0 秒并发出新的尝试
- CB 从
Broken
过渡到 Hal-Open
Probe
已调用但失败
- ...
此解决方案的最大问题是阻塞。不幸的是 onBreak
没有异步版本。 (重试确实有 onRetryAsync
,您可以在其中使用 Task.Delay
而不是 Thread.Sleep
)
第二个问题是它依赖于current implementation。如果 onBreak
在不同的线程上执行并且立即抛出异常,则此解决方案将不起作用。
在 Polly 上修改 Duration Break 的正确方法是什么? 我知道他们在文档中提到实施(PolicyRegistry)。 有这方面的例子吗? 我在一个 WinService 中实现了 Polly CircuitBreaker。
断路器未设计为在断开时使用不同的睡眠持续时间。
In case of Retry you have the ability to provide a function,称为 sleepDurationProvider
,由策略调用以确定发出下一次尝试之前的实际睡眠持续时间。
所以,简而言之 by design it is not supported。我将向您展示一种解决方法,但我不 推荐使用它。我会在示例代码后给出推理。
为了简单起见,我们采用以下方法:
static int Probe()
{
Console.WriteLine("Probe has been called");
throw new NotSupportedException();
}
- 它打印出该方法已被调用的事实,然后立即失败。
- 恕我直言:不是一个真正有用的功能 :D
让我们定义一个辅助方法,每次调用时都会增加时间段(>> 睡眠持续时间):
static IEnumerable<TimeSpan> GetSleepDuration()
{
for (int i = 1; i < 10; i++)
{
yield return TimeSpan.FromSeconds(i);
}
}
- 这(或多或少)取代了 Retry 的
sleepDurationProvider
。
现在是时候定义我们的断路器策略了:
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"));
- 我们得到了
GetSleepDuration
的迭代器
- 我们将连续失败计数设置为 1,因此在每次
Probe
调用后 CB 都会中断 - 我们将
durationOfBreak
设置为零,因为我们将在onBreak
<< 解决方法 中等待
- 我们打印出睡眠持续时间然后我们睡觉,最后我们增加下一次休息的睡眠持续时间
为了简化我们的测试,让我们定义一个重试策略:
var retry = Policy<int>
.Handle<NotSupportedException>()
.WaitAndRetryForever(_ => TimeSpan.FromSeconds(0),
onRetry: (_, __) => Console.WriteLine("Retry is triggered"));
- 它处理
Probe
的异常 - 它永远重试并在每次重试调用之间等待 0 秒
让我们连接策略和 运行 测试:
Policy.Wrap(retry, cb).Execute(() => Probe());
输出将是:
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
...
Probe
已调用但失败- CB 从
Open
过渡到Broken
onBreak
被调用,阻塞执行1秒PolicyWrap
将问题升级为重试- 重试等待 0 秒并发出新的尝试
- CB 从
Broken
过渡到Hal-Open
Probe
已调用但失败- ...
此解决方案的最大问题是阻塞。不幸的是 onBreak
没有异步版本。 (重试确实有 onRetryAsync
,您可以在其中使用 Task.Delay
而不是 Thread.Sleep
)
第二个问题是它依赖于current implementation。如果 onBreak
在不同的线程上执行并且立即抛出异常,则此解决方案将不起作用。