即使捕获到异常, Polly也不会重试



我的HTTP服务配置如下:

services
.AddHttpClient<ISomeHttpService, SomeHttpService>((Action<HttpClient>) (client =>
{
client.BaseAddress = new Uri(configuration.BaseAddress);
client.Timeout = TimeSpan.FromSeconds(10);
}))
.AddPolicyHandler(GetPollyPolicy())
.AddHttpMessageHandler<DistributedCachedHttpClientHandler>();
// .....

private static IAsyncPolicy<HttpResponseMessage> GetPollyPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrInner<Exception>() // I will probably use TimeoutException, for now I'm checking all possible options
.WaitAndRetryAsync(2, _ => TimeSpan.FromMilliseconds(100), 
(exception, timeSpan) =>
{
_ = "breakpoint";
});
}

如果SomeHttpService发出的请求返回500,它工作得很好。Polly尝试再试2次。

但是,如果请求花费的时间超过10秒(超过配置的超时时间),则不会发生重试。我甚至在Polly的动作中设置了一个断点,我看到当超时发生时,断点被击中!但是,当我继续执行程序时,没有执行重试,并且我的web API在500之后直接失败。

怎么了?

我也试过用Or<Exception>()代替OrInner<Exception>()

TL;DR:观察到的行为是HttpClientTimeout如何覆盖所有重试尝试的方式。


问题的根本原因是HttpClientTimeout被认为是全局超时而不是本地超时:

  • 全局表示全局,包括所有重试尝试
  • 本地意味着每次重试

如果你想定义一个本地超时,那么你必须结合重试和超时策略:

var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(5);
var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.OrInner<TimeoutRejectedException>()
.WaitAndRetryAsync(2, _ => TimeSpan.FromMilliseconds(10));
var combinedPolicy = Policy.WrapAsync(retryPolicy, timeoutPolicy);

请注意,Policy.WrapAsync的参数顺序很重要。

上面的例子定义了一个每个请求超时策略(inner)和一个重试策略(outer),它知道潜在的超时(TimeoutRejectedException)。

您可以定义两个超时策略,其中一个在本地执行,而另一个在全局执行:

var combinedPolicy = Policy.WrapAsync(globalTimeout, retryPolicy, localTimeout);

最新更新