使用polly c#在http请求超时时重试多次

Retry multiple times when http request times out using polly c#

我的初衷是在请求本身超时时重试多次,例如在尝试与另一个关闭了几秒钟的微服务通信时希望这是暂时的失败。如果有一个更简单的解决方案来做到这一点就足够了。 我决定使用包装策略手动设置每次重试的超时时间,希望能达到相同的结果。

我在这里看到了不使用 httpclientfactory 的类似解决方案 ,但它对我不起作用。

我的代码如下所示:

services.AddHttpClient("retryclient", client =>
{
    client.Timeout = TimeSpan.FromSeconds(100);
}).AddPolicyHandler((servs, request) =>
    Policy.HandleResult<HttpResponseMessage>(r =>
        {
            return r.StatusCode == HttpStatusCode.NotFound; //(1)
        }).
.OrTransiesntHttpError().
WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(retryAttempt),
    onRetry: (exception, timespan, retryAttempt, context) =>
        { // using servs to log // });
}).WrapAsync(Policy.TimeoutAsync(1)));

我已经检查过当我尝试访问 'not-found' 地址而不包含超时策略时重试策略是否有效并且它工作正常。我还尝试将第 (1) 行与状态代码 HttpStatusCode.RequestTimeout 一起使用,而不是针对我的情况使用 not found ,但它不起作用。

当我使用包装并尝试访问已关闭的服务时,它会像我预期的那样在第一次尝试时抛出 Polly.Timeout.TimeoutRejectedException,但不会再次重试。我想不出一种方法来重试多次,要么为每次重试设置超时,要么只是在请求本身超时时不使用超时策略。

编辑:进一步阅读 https://cm.engineering/transient-timeouts-and-the-retry-rabbit-hole-net-4-5-f406cebbf194 后,我的问题似乎出在策略处理中,我无权访问 HttpClient 的取消令牌。我假设我可以通过覆盖 link 中所示的 sendAsync 方法来修复它。在创建工厂时有没有一种优雅的方法来做同样的事情?

Polly documentation on HttpClientFactory covers this in a section labelled applying timeouts:

You may want the retry policy to retry if any individual try timed out. To do this, make the retry policy handle the TimeoutRejectedException which Polly's timeout policy throws.

所以:

services.AddHttpClient("retryclient", client =>
{
    client.Timeout = TimeSpan.FromSeconds(100);
}).AddPolicyHandler((servs, request) =>
    Policy.HandleResult<HttpResponseMessage>(r =>
        {
            return r.StatusCode == HttpStatusCode.NotFound; //(1)
        }).
.OrTransientHttpError()
.Or<TimeoutRejectedException>() // ** ADDED **
.WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(retryAttempt),
    onRetry: (exception, timespan, retryAttempt, context) =>
        { // using servs to log // });
})
.WrapAsync(Policy.TimeoutAsync(1)));

Polly 将 CancellationToken 正确传递给内部 .SendAsync() 调用;不需要对此进行任何更改。