Polly CircuitBreaker - 动态中断持续时间

Posted

技术标签:

【中文标题】Polly CircuitBreaker - 动态中断持续时间【英文标题】:Polly CircuitBreaker - Dynamic Duration of Break 【发布时间】:2021-12-03 23:46:43 【问题描述】:

在 Polly 上修改 Duration Break 的正确方法是什么? 我知道他们在文档中提到实施(PolicyRegistry)。 有这方面的例子吗? 我在一个 WinService 中实现 Polly CircuitBreaker。

【问题讨论】:

将您的策略​​添加到策略注册表,注入策略注册表,替换策略注册表中的策略(因为策略是不可变的),下次需要该策略时,使用新的策略跨度> 能否详细说明动态部分?是否要使用 429 的 Retry-After 标头来设置 durationOfBreak?或者你想怎么设置? 我需要实时更改中断的持续时间...例如:第一次休息 1 分钟,第二次休息 1×2 分钟...等 【参考方案1】:

Circuit Breaker 并非设计为在每次中断时使用不同的睡眠持续时间。

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

让我们定义一个辅助方法,每次调用时都会增加时间段(>> sleep duration):

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 CircuitBreaker - 动态中断持续时间的主要内容,如果未能解决你的问题,请参考以下文章

Polly

Polly 熔断策略

Polly

CircuitBreaker 未从 yaml 文件加载默认值

Polly 同步重试

Polly的多种弹性策略介绍和简单使用