重试使用Polly。

3
这两个重试策略是否表示相同的意思?
Policy
    .Handle<SomeExceptionType>()
    .WaitAndRetry(
        new[]
        {
            TimeSpan.FromMinutes(1),
            TimeSpan.FromMinutes(1),
            TimeSpan.FromMinutes(1)
        });

Policy
    .Handle<SomeExceptionType>()
    .WaitAndRetry(
        3,
        retryAttempt => TimeSpan.FromMinutes(1)
    );
1个回答

5

是的,它们是相同的。

这两种代码都定义了一个策略,最多执行4次相同的操作:初始尝试+三个额外的尝试。

两个重载之间的主要区别如下:

  • 前者以静态方式定义惩罚
    • 它预定义了不同尝试之间的延迟
  • 后者以动态方式定义惩罚
    • 它可以根据即将发生的重试计算延迟

在您的特定示例中,您的第二个选择可以定义为:

Policy
    .Handle<SomeExceptionType>()
    .WaitAndRetry(
        3,
        _ => TimeSpan.FromMinutes(1)
    );

使用丢弃操作符,您明确声明在 sleepDurationProvider 中不使用该参数来计算新的延迟。


为了清晰起见,在本文中,我将惩罚延迟休眠术语用作同义词。


更新#1

以下是两个例子,您可以利用动态惩罚计算。

指数退避+抖动

与其在每次尝试之间等待相同的时间,建议使用越来越长的延迟,以给下游系统自我修复留出空间。例如:2、4、8...

抖动只是一个小的随机数,以避免所有客户端尝试在同一时间发送重试请求。因此,它会分散/分散客户端的重试尝试时间。

const int maxDelayInMilliseconds = 32 * 1000;
var jitterer = new Random();
Policy
  .Handle<HttpRequestException>()
  .WaitAndRetryForever(
      retryAttempt =>
      {
          var calculatedDelayInMilliseconds = Math.Pow(2, retryAttempt) * 1000;
          var jitterInMilliseconds = jitterer.Next(0, 1000);

          var actualDelay = Math.Min(calculatedDelayInMilliseconds + jitterInMilliseconds, maxDelayInMilliseconds);
          return TimeSpan.FromMilliseconds(actualDelay);
      }
  );

断路器感知重试

如果您正在使用断路器来避免在其自我修复时淹没下游系统,那么可以使您的重试意识到此操作。

默认情况下,所有策略都是独立的,它们彼此不知道。如果在 CB 处于打开状态时发出重试尝试,则会收到一个 BrokenCircuitException 异常(因此会快速停止执行)。但是,您可以根据 CB 的状态动态计算延迟时间,以便跳过这些不必要的重试。

断路器定义:

Policy<HttpResponseMessage>
    .HandleResult(res => res.StatusCode == HttpStatusCode.InternalServerError)
    .CircuitBreakerAsync(3, TimeSpan.FromSeconds(2),
       onBreak: (dr, ts, ctx) => { ctx[SleepDurationKey] = ts; },
       onReset: (ctx) => { ctx[SleepDurationKey] = null; });

重试定义

Policy<HttpResponseMessage>
    .HandleResult(res => res.StatusCode == HttpStatusCode.InternalServerError)
    .Or<BrokenCircuitException>()
    .WaitAndRetryAsync(4,
        sleepDurationProvider: (c, ctx) =>
        {
            if (ctx.ContainsKey(SleepDurationKey))
                return (TimeSpan)ctx[SleepDurationKey];
            return TimeSpan.FromMilliseconds(200);
        });

这个高级用例的详细描述可以在这里找到。


1
谢谢。如果我需要在重试时添加日志,例如“正在重试..第1次尝试,共{totalnumberofretries}次”,我该如何做? - user989988
@user989988 在 WaitAndRetry 中,您可以提供一个委托(称为 onRetry),在惩罚性休眠之前进行日志记录。您可以在最后一个链接中看到一个示例。 - Peter Csala

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接