如何使用 Polly 筛选重试策略的特定终结点

How to filter specific endpoint for retry policy using Polly

提问人:Rafael 提问时间:8/3/2023 最后编辑:Peter CsalaRafael 更新时间:8/3/2023 访问量:208

问:

如何使用 Polly 筛选重试策略的特定终结点

所有客户端请求都将重试。如何禁用重试策略特定的 api?MyServiceHttpClient

services.AddHttpClient<MyServiceHttpClient>(client =>
{
    /* configuration */
})
.AddPolicyHandler((serviceProvider, request) => 
    HttpPolicyExtensions.HandleTransientHttpError()
        .WaitAndRetryAsync(3, 
            sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), 
            onRetry: (outcome, timespan, retryAttempt, context) =>
            {
                serviceProvider.GetService<ILogger<MyServiceHttpClient>>()
                    .LogWarning("Delaying for {delay}ms, then making retry {retry}.", timespan.TotalMilliseconds, retryAttempt);
            }
            ));
c# 。网 依赖注入 波莉 重试逻辑

评论

0赞 Guru Stron 8/3/2023
最简单的方法是将其一分为二。

答:

1赞 Guru Stron 8/3/2023 #1

您可以尝试使用无操作策略:

builder.Services.AddHttpClient<MyServiceHttpClient>(client =>
    {
        /* configuration */
    })
    .AddPolicyHandler((serviceProvider, request) =>
        request.RequestUri.PathAndQuery.StartsWith("/api/") // your predicate
            ? Policy.NoOpAsync<HttpResponseMessage>() // <- no op for matching predicate
            : HttpPolicyExtensions.HandleTransientHttpError()
                .WaitAndRetryAsync(3,
                    sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
                    onRetry: (outcome, timespan, retryAttempt, context) =>
                    {
                        serviceProvider.GetService<ILogger<MyServiceHttpClient>>()
                            .LogWarning("Delaying for {delay}ms, then making retry {retry}.",
                                timespan.TotalMilliseconds, retryAttempt);
                    }
                ));

或者另一种方法是重复逻辑,但添加相应的过滤器。HandleTransientHttpError

1赞 Peter Csala 8/3/2023 #2

尽管 Guru Stron 提出的解决方案有效,但恕我直言,维护起来非常困难。

让我向您介绍另一种解决方案。有许多不同的重载。有些需要参数,而另一些则不需要。如果您使用需要参数的重载,则可以执行以下操作:WaitAndRetryAsyncretryCountIEnumerable<TimeSpan> retryDurations

.AddPolicyHandler((serviceProvider, request) =>
    HttpPolicyExtensions.HandleTransientHttpError()
        .WaitAndRetryAsync(
            GetRetryDelays(request), 
            (_, timespan, retryAttempt, __) =>
            {
                //logging               
            }));

现在让我们看看相关的实现GetRetryDelays

private static readonly Uri DoNotRetryUri = new("https://...");
private const int MaxRetryAttempt = 3;
private static IEnumerable<TimeSpan> GetRetryDelays(HttpRequestMessage request)
{
    if (request.RequestUri == DoNotRetryUri)
        return Array.Empty<TimeSpan>();

    return Enumerable.Range(0, MaxRetryAttempt)
        .Select(retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))
        .ToArray();
}
  • 如果请求 uri 与常量相同,则它不会执行任何重试
  • 如果请求 uri 与常量不同,则它会创建一个具有以下值的睡眠持续时间数组
[
   00:00:01
   ,
   00:00:02
   ,
   00:00:04
]