HttpClient Polly WaitAndRetry 策略

csc*_*h99 5 c# rest dotnet-httpclient polly retry-logic

有人知道为什么下面的策略在 3 次而不是 10 次后停止重试吗?

IAsyncPolicy<HttpResponseMessage> httpWaitAndRetryPolicy =
     Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
          .OrHandle<Exception>(r => true)
          .WaitAndRetryAsync(10, retryAttempt => TimeSpan.FromSeconds(2));
Run Code Online (Sandbox Code Playgroud)

我将重试尝试设置为 10 并测试 http post 调用,但 BadRequest 失败。但只重试了3次就停止了,直到超时并抛出异常

IAsyncPolicy<HttpResponseMessage> httpWaitAndRetryPolicy =
     Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
          .OrHandle<Exception>(r => true)
          .WaitAndRetryAsync(10, retryAttempt => TimeSpan.FromSeconds(2));
Run Code Online (Sandbox Code Playgroud)
var serviceProvider = serviceConnection.AddHttpClient(connection.Name, c =>
        {
            c.BaseAddress = new Uri(connection.BaseUrl);
            c.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{connection.UserName}:{connection.Password}")));
            c.Timeout = connection.Timeout; // Timeout is TimeSpan.FromSeconds(120)
        })
    .AddPolicyHandler(httpWaitAndRetryPolicy)
    .Services.BuildServiceProvider();

HttpClientFactories.Add(connection.Name, serviceProvider.GetService<IHttpClientFactory>());
Run Code Online (Sandbox Code Playgroud)

确认了问题的根本原因:我不知道是什么原因导致了该症状,但看起来请求连接不会被释放,除非显式调用Dispose HttpResponseMessage OnRetry. 当前的解决方案是设置OnRetryWaitAndRetryAsync配置响应。一切正常,无需更改ServicePointManager.DefaultConnectionLimit

Pet*_*ala 6

你的超时

正如我所看到的,您在 HttpClient 级别上有一个全局 1 分钟超时。TaskCanceledException即使您可能期望,这也会引发TimeoutException

如果您希望接收TimeoutException,则必须通过RequestTimeout的属性指定基于请求的超时HttpRequestMessage。欲了解更多详情,请查看以下链接

您的重试

您的重试逻辑定义了 3 次(或 10 次)重试,并有 5 秒的惩罚。3 次重试意味着 4 次尝试,因为有一个初始(第 0 个)请求,该请求超出了重试范围。如果失败,则第一次重试将成为第二次尝试。

所以流程将如下所示:

  1. 发出初始请求 << 第一次尝试
  2. 初始请求失败
  3. 触发重试逻辑
  4. 5秒处罚曝光
  5. 第一次重试逻辑触发 << 第二次尝试
  6. 第二次尝试失败
  7. 触发重试逻辑
  8. 5秒处罚曝光
  9. 第二次重试逻辑触发 << 第三次尝试
  10. ...

如果所有这些都不能在一分钟内完成,那么 HttpClient 将TaskCanceledExpcetion因全局超时而抛出异常。

Polly 的超时政策

Polly 还支持本地和全局超时策略。有一个超时策略,可以以两种方式使用。

如果您的超时策略包含在重试中,它可以充当本地超时: retryPolicy.WrapAsync(timeoutPolicy);

如果您的重试策略包含在超时内,它可以充当全局超时: timeoutPolicy.WrapAsync(retryPolicy);

当然,您也可以同时设置全局和本地超时: Policy.WrapAsync(globalTimeoutPolicy, retryPolicy, localTimeoutPolicy);

我强烈鼓励您考虑使用 Polly 的 Timeout 而不是 HttpClient 的 Timeout,以便有一个地方可以定义弹性策略。

请记住,TimeoutRejectedException如果超时后没有响应,超时策略将抛出异常。因为您的重试会处理所有类型的异常 ( .OrHandle<Exception>()),所以您不需要修改重试策略。

Polly 的瞬时故障的错误处理

有一个名为Microsoft.Extensions.Http.Polly ( 1 ) 的 nuget 包,它定义了几个有用的实用程序。其中之一是HttpPolicyExtensions.HandleTransientHttpError()

它捕获HttpRequestException并检查响应的状态代码是否为5xx408 (RequestTimeout)。

也可能值得考虑使用它。

调试策略

每个不同的策略都定义了回调,以提供了解它们如何工作的能力。如果重试,则分别调用onRetryoronRetryAsync进行同步或异步重试。通过在您的内部提供以下委托,WaitAndRetryAsync您可以获得真正有用​​的信息:

onRetryAsync: (exception, delay, times, context) => {
  //TODO: logging
}
Run Code Online (Sandbox Code Playgroud)