【问题标题】:Cannot make Polly Timeout Policy override the HttpClient default timeout无法使 Polly 超时策略覆盖 HttpClient 默认超时
【发布时间】:2020-08-18 17:41:11
【问题描述】:

我正在使用 Polly 重试策略,并且正如预期的那样,在重试过程中,HttpClient 达到了 100 秒超时。我尝试了几种不同的方法来合并 Polly Timeout 策略,以将超时移动到每次重试而不是总超时,但是 100 秒超时一直触发。

我已经阅读了大约 5 个 StackOverflow 问题,这些问题都说要包装策略,我什至在 Polly wiki 上找到了说要调用 AddPolicyHandler 两次的演示。那也没有用。我确信我有一些非常基本的错误。请向我解释我的方式的错误。

我正在使用 .net core 5 preview 7 和当前 Polly nuget 包。

类型化 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;
}

【问题讨论】:

    标签: c# .net-core polly httpclientfactory


    【解决方案1】:

    根据提供的代码,我可以看到以下弹性策略:

    100 秒全局超时

    5 次重试(= 5+1 次尝试)

    指数退避逻辑

    10 秒本地超时


    如果我正确理解您的问题,那么您正在寻找增加全局超时的解决方案。

    最简单的解决方案 (1) 是将 HttpClient 实例的 Timeout 属性从默认的 100 增加到所需的值。如果超过此超时,则实例将抛出 OperationCanceledException 并且无法建立进一步的重试尝试。

    如果HttpClient 实例在不同组件之间共享/重用,那么您可能需要更改每次使用的全局超时。您可以通过在 HttpClient 的全局超时和您的重试策略之间引入新的超时策略来克服这个问题。

    因此,您最终可能会得到以下设置:

    200 秒全局超时(通过 HttpClient

    150 秒整体/总体超时(通过外部超时策略)

    5 次重试(= 5+1 次尝试)

    指数退避逻辑

    10 秒本地超时

    在这种特殊情况下,我建议像这样使用Policy.WrapAsync (1):

    Policy.WrapAsync(OverallTimeoutPolicy(), RetryPolicy(), LocalTimeoutPolicy());
    

    【讨论】:

    • 不,我不想增加全局超时,我希望超时是重试。如果将全局超时设置为 300 秒(以涵盖重试),则第一次尝试不会超时 5 分钟。
    • @SOHODeveloper 我是否正确理解您的 10 秒本地超时无效?
    • 可能有效果。我没有打它。问题是 3 次重试期间的 100 次命中,而我再也没有进行其余的重试。我已经通过强制看起来像暂时性错误的方式对此进行了测试。我对我阅读的代码和 cmets 的理解是,重试代码应该以某种方式“重置”全局超时。
    • 所以我应该将我的全局超时设置为大数字,以涵盖我在挂钟时间内的所有重试,包括重试之间的等待时间。您在上面建议了另一个策略包装。我在示例或文档中没有看到这样的用法。我需要吗?如果是这样,请为我和未来的人添加一些解释,说明为什么也需要它。
    • 感谢您的所有讨论。我已经阅读了您引用的问题中的信息。在大约 3 或 4 次阅读中,我捡到了我之前错过的一两个单词,我们的讨论让我朝着不同的方向思考,所以我对一些事情做出了不同的解释,我相信我知道如何进步。我目前没有处理这个问题,所以我要过一段时间才能确定。我标记为回答,因为你坚持我。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2019-08-22
    • 2020-10-29
    • 2017-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-29
    相关资源
    最近更新 更多