无法使 Polly 超时策略覆盖 HttpClient 默认超时
Cannot make Polly Timeout Policy override the HttpClient default timeout
我正在使用 Polly 重试策略,正如预期的那样,在重试过程中 HttpClient
达到了 100 秒超时。我已经尝试了几种不同的方法来合并 Polly 超时策略以将超时移动到每次重试而不是总超时,但是 100 秒超时一直在触发。
我已经阅读了大约 5 个 Whosebug 问题,它们都说要包装策略,我什至在 Polly wiki 上找到了说调用 AddPolicyHandler
两次的演示。那也不管用。我确定我有一些非常基本的错误。请向我解释我方法的错误。
我正在使用 .net core 5 preview 7 和当前的 Polly nuget 包。
Typed HttpClient 注册
serviceCollection.AddHttpClient<APIWrappers.SendGridClientEmail, APIWrappers.SendGridClientEmail>((c) =>
{
c.BaseAddress = new Uri("https://api.sendgrid.com/v3a/");
})
.AddPolicyHandler((services, req) => TransientLogAndRetry<APIWrappers.SendGridClientEmail>(services, req)
.WrapAsync(Policy.TimeoutAsync<HttpResponseMessage>(10)));
策略定义
public IAsyncPolicy<HttpResponseMessage> TransientLogAndRetry<T>(IServiceProvider services, object req)
{
Console.WriteLine($"Name: {typeof(T).Name} - Time: {DateTime.Now}");
return HttpPolicyExtensions.HandleTransientHttpError().
OrResult((rsp) => rsp.StatusCode == System.Net.HttpStatusCode.TooManyRequests).
Or<Polly.Timeout.TimeoutRejectedException>().
WaitAndRetryAsync(5, GetRetryTime,
#pragma warning disable CS1998
async (ex, ts, rc, ctx) =>
{
((STS.Diagnostics.LoggerFactory)services.GetService<ILoggerFactory>())?.CreateLogger<T>().
Warn(this, "HTTP request above will retry in {0}", ts);
}
#pragma warning restore CS1998
);
}
延迟/惩罚计算
private TimeSpan GetRetryTime(int retryCount, DelegateResult<HttpResponseMessage> response, Context context)
{
TimeSpan result;
long unix;
Console.WriteLine($"Count: {retryCount} - Time: {DateTime.Now}");
if (response.Result is null || response.Result.StatusCode != System.Net.HttpStatusCode.TooManyRequests)
result = TimeSpan.FromSeconds(Math.Min(Math.Pow(Math.Sqrt(retryCount * 2), 5), 60 * 60));
else
{
unix = response.Result.Headers.GetValues("X-RateLimit-Reset").Select((v) => long.Parse(v)).First();
result = DateTime.UtcNow - DateTimeOffset.FromUnixTimeSeconds(unix);
}
Console.WriteLine(result);
return result;
}
根据提供的代码,我可以看到以下弹性策略:
100 seconds global timeout
5 retries (= 5+1 attempts)
Exponential back-off logic
10 seconds local timeout
如果我对你的问题的理解正确,那么你正在寻找增加全局超时的解决方案。
最简单的解决方案 (1) 是将 HttpClient
实例的 Timeout
属性 从默认值 100 增加到所需值。如果超过此超时,则实例将抛出 OperationCanceledException
并且无法建立进一步的重试尝试。
如果 HttpClient
实例在不同组件之间共享/重复使用,那么您可能需要更改每次使用的全局超时。您可以通过在 HttpClient 的全局超时和重试策略之间引入新的超时策略来克服这个问题。
因此,您可能会得到以下设置:
200 seconds global timeout (by HttpClient
150 seconds overall / overarching timeout (by outer timeout policy)
5 retries (= 5+1 attempts)
Exponential back-off logic
10 seconds local timeout
在这种特殊情况下,我建议像这样使用 Policy.WrapAsync
(1):
Policy.WrapAsync(OverallTimeoutPolicy(), RetryPolicy(), LocalTimeoutPolicy());
我正在使用 Polly 重试策略,正如预期的那样,在重试过程中 HttpClient
达到了 100 秒超时。我已经尝试了几种不同的方法来合并 Polly 超时策略以将超时移动到每次重试而不是总超时,但是 100 秒超时一直在触发。
我已经阅读了大约 5 个 Whosebug 问题,它们都说要包装策略,我什至在 Polly wiki 上找到了说调用 AddPolicyHandler
两次的演示。那也不管用。我确定我有一些非常基本的错误。请向我解释我方法的错误。
我正在使用 .net core 5 preview 7 和当前的 Polly nuget 包。
Typed HttpClient 注册
serviceCollection.AddHttpClient<APIWrappers.SendGridClientEmail, APIWrappers.SendGridClientEmail>((c) =>
{
c.BaseAddress = new Uri("https://api.sendgrid.com/v3a/");
})
.AddPolicyHandler((services, req) => TransientLogAndRetry<APIWrappers.SendGridClientEmail>(services, req)
.WrapAsync(Policy.TimeoutAsync<HttpResponseMessage>(10)));
策略定义
public IAsyncPolicy<HttpResponseMessage> TransientLogAndRetry<T>(IServiceProvider services, object req)
{
Console.WriteLine($"Name: {typeof(T).Name} - Time: {DateTime.Now}");
return HttpPolicyExtensions.HandleTransientHttpError().
OrResult((rsp) => rsp.StatusCode == System.Net.HttpStatusCode.TooManyRequests).
Or<Polly.Timeout.TimeoutRejectedException>().
WaitAndRetryAsync(5, GetRetryTime,
#pragma warning disable CS1998
async (ex, ts, rc, ctx) =>
{
((STS.Diagnostics.LoggerFactory)services.GetService<ILoggerFactory>())?.CreateLogger<T>().
Warn(this, "HTTP request above will retry in {0}", ts);
}
#pragma warning restore CS1998
);
}
延迟/惩罚计算
private TimeSpan GetRetryTime(int retryCount, DelegateResult<HttpResponseMessage> response, Context context)
{
TimeSpan result;
long unix;
Console.WriteLine($"Count: {retryCount} - Time: {DateTime.Now}");
if (response.Result is null || response.Result.StatusCode != System.Net.HttpStatusCode.TooManyRequests)
result = TimeSpan.FromSeconds(Math.Min(Math.Pow(Math.Sqrt(retryCount * 2), 5), 60 * 60));
else
{
unix = response.Result.Headers.GetValues("X-RateLimit-Reset").Select((v) => long.Parse(v)).First();
result = DateTime.UtcNow - DateTimeOffset.FromUnixTimeSeconds(unix);
}
Console.WriteLine(result);
return result;
}
根据提供的代码,我可以看到以下弹性策略:
100 seconds global timeout
5 retries (= 5+1 attempts)
Exponential back-off logic
10 seconds local timeout
如果我对你的问题的理解正确,那么你正在寻找增加全局超时的解决方案。
最简单的解决方案 (1) 是将 HttpClient
实例的 Timeout
属性 从默认值 100 增加到所需值。如果超过此超时,则实例将抛出 OperationCanceledException
并且无法建立进一步的重试尝试。
如果 HttpClient
实例在不同组件之间共享/重复使用,那么您可能需要更改每次使用的全局超时。您可以通过在 HttpClient 的全局超时和重试策略之间引入新的超时策略来克服这个问题。
因此,您可能会得到以下设置:
200 seconds global timeout (by HttpClient
150 seconds overall / overarching timeout (by outer timeout policy)
5 retries (= 5+1 attempts)
Exponential back-off logic
10 seconds local timeout
在这种特殊情况下,我建议像这样使用 Policy.WrapAsync
(1):
Policy.WrapAsync(OverallTimeoutPolicy(), RetryPolicy(), LocalTimeoutPolicy());