我可以在 PolicyWrap 中跨策略共享 retryCount 而不是重置它们吗?
Can I share retryCount across policies in a PolicyWrap instead of them resetting?
我目前配置了两个重试策略,用于进行一些 api 调用,这些调用正在使用 PolicyWrap
:
- 用于捕获 429 速率限制错误并遵守 retry-after header
的 WaitAndRetry 策略
- 用于处理 timeouts/transient 错误的常规重试策略,无需等待并且可以立即重试调用
是否可以将它们配置为共享同一个重试计数器?举例来说,我想配置 5 次尝试发送消息,而不管哪个策略捕获它。
我当前配置的简化示例:
int maxAttempts = 5;
AsyncRetryPolicy RetryAfter = Policy
.Handle<HttpResponseException>(e => e.Response.StatusCode == HttpStatusCode.TooManyRequests)
.WaitAndRetryAsync(retryCount: maxAttempts, i => TimeSpan.FromSeconds(1));
AsyncRetryPolicy RetryNow = Policy
.Handle<HttpResponseException>(e => e.Response.StatusCode == HttpStatusCode.RequestTimeout)
.RetryAsync(retryCount: maxAttempts);
AsyncPolicyWrap ApiPolicy = Policy.WrapAsync(RetryNow, RetryAfter);
我正在使用 onRetryAsync
记录重试尝试。当它执行时,我得到如下输出,其中 RetryAfter
策略会在 RetryNow
策略触发时重置它的重试计数器。
Received error code ServerTimeout with internal status 408. Retry attempt #1
Received error code ServerError with internal status 429. Retry attempt #1 after 00:00:00.6010000
Received error code ServerTimeout with internal status 408. Retry attempt #2
Received error code ServerError with internal status 429. Retry attempt #1 after 00:00:00.5000000
Received error code ServerError with internal status 429. Retry attempt #2 after 00:00:00.3880000
Received error code ServerTimeout with internal status 408. Retry attempt #3
Received error code ServerError with internal status 429. Retry attempt #1 after 00:00:00.5230000
Received error code ServerTimeout with internal status 408. Retry attempt #4
Received error code ServerError with internal status 429. Retry attempt #1 after 00:00:00.5000000
Received error code ServerError with internal status 429. Retry attempt #2 after 00:00:00.1740000
Received error code ServerTimeout with internal status 408. Retry attempt #5
这意味着从理论上讲,总执行次数可能远大于策略上配置的 retryCount
总和。理想情况下,我希望这总共执行最多 5 次重试,但在这一点上,我很乐意让这两个策略都遵守其配置的 retryCount
最多 10 次重试。就目前而言,此配置的理论最大值似乎总计大于 35:第 1 次初始执行 +(5 RetryAfters
+ 1 RetryNow
每次 RetryNow
尝试重复)
我是不是做错了什么?有没有推荐的方法来处理这种情况?我仍在努力了解策略配置,所以我假设我在这里缺少某种 recommended/best 实践。否则这似乎是一个重大疏忽,如果是这种情况,我肯定不会是唯一 运行 解决这个问题的人,但我在文档中找不到任何相关信息。
方案一:将两种重试策略合二为一
您可以在一项政策中处理这两种例外情况。您可以使用 .Or<>()
语法指定第二个异常,并使用 this overload 根据异常(和其他因素)选择重试前等待的持续时间:
AsyncRetryPolicy ApiPolicy = Policy
.Handle<HttpResponseException>(e => e.Response.StatusCode == HttpStatusCode.TooManyRequests)
.Or<HttpResponseException>(e => e.Response.StatusCode == HttpStatusCode.RequestTimeout)
.WaitAndRetryAsync(retryCount: maxAttempts,
sleepDurationProvider: (i, ex, ctx) =>
ex.Response.StatusCode == HttpStatusCode.TooManyRequests
? TimeSpan.FromSeconds(1)
: TimeSpan.Zero,
onRetryAsync: (ex, span, i, ctx) => /* whatever you have for logging */
);
此重试政策将限制为 1 + maxAttempts
次总体尝试,并反映您原始配置中的重试延迟。
解决方案 2:控制整体执行时间以抑制 'excessive' 重试
或者,如果您发现将两次重试表示为单独的策略(即原始的 RetryAfter
和 RetryNow
)更清楚,那么另一种选择是包装一个 [=17= 】 在他们之外。
TimeoutPolicy
将限制组合执行的总持续时间 - 包括所有尝试和重试之间的等待 - 提供一种基于时间的方法来防止组合重试意外增加。
// RetryAfter and RetryNow exactly as in your question. Then:
AsyncTimeoutPolicy OverallTimeout = Policy.TimeoutAsync(TimeSpan.FromSeconds(45));
IAsyncPolicy ApiPolicy = Policy.WrapAsync(OverallTimeout, RetryNow, RetryAfter);
如果你想要每次尝试超时,你也可以在 PolicyWrap 的内端引入它。
AsyncTimeoutPolicy OverallTimeout = Policy.TimeoutAsync(TimeSpan.FromSeconds(45));
AsyncTimeoutPolicy TimeoutPerTry = Policy.TimeoutAsync(TimeSpan.FromSeconds(10));
IAsyncPolicy ApiPolicy = Policy.WrapAsync(OverallTimeout, RetryNow, RetryAfter, TimeoutPerTry);
我目前配置了两个重试策略,用于进行一些 api 调用,这些调用正在使用 PolicyWrap
:
- 用于捕获 429 速率限制错误并遵守 retry-after header 的 WaitAndRetry 策略
- 用于处理 timeouts/transient 错误的常规重试策略,无需等待并且可以立即重试调用
是否可以将它们配置为共享同一个重试计数器?举例来说,我想配置 5 次尝试发送消息,而不管哪个策略捕获它。
我当前配置的简化示例:
int maxAttempts = 5;
AsyncRetryPolicy RetryAfter = Policy
.Handle<HttpResponseException>(e => e.Response.StatusCode == HttpStatusCode.TooManyRequests)
.WaitAndRetryAsync(retryCount: maxAttempts, i => TimeSpan.FromSeconds(1));
AsyncRetryPolicy RetryNow = Policy
.Handle<HttpResponseException>(e => e.Response.StatusCode == HttpStatusCode.RequestTimeout)
.RetryAsync(retryCount: maxAttempts);
AsyncPolicyWrap ApiPolicy = Policy.WrapAsync(RetryNow, RetryAfter);
我正在使用 onRetryAsync
记录重试尝试。当它执行时,我得到如下输出,其中 RetryAfter
策略会在 RetryNow
策略触发时重置它的重试计数器。
Received error code ServerTimeout with internal status 408. Retry attempt #1
Received error code ServerError with internal status 429. Retry attempt #1 after 00:00:00.6010000
Received error code ServerTimeout with internal status 408. Retry attempt #2
Received error code ServerError with internal status 429. Retry attempt #1 after 00:00:00.5000000
Received error code ServerError with internal status 429. Retry attempt #2 after 00:00:00.3880000
Received error code ServerTimeout with internal status 408. Retry attempt #3
Received error code ServerError with internal status 429. Retry attempt #1 after 00:00:00.5230000
Received error code ServerTimeout with internal status 408. Retry attempt #4
Received error code ServerError with internal status 429. Retry attempt #1 after 00:00:00.5000000
Received error code ServerError with internal status 429. Retry attempt #2 after 00:00:00.1740000
Received error code ServerTimeout with internal status 408. Retry attempt #5
这意味着从理论上讲,总执行次数可能远大于策略上配置的 retryCount
总和。理想情况下,我希望这总共执行最多 5 次重试,但在这一点上,我很乐意让这两个策略都遵守其配置的 retryCount
最多 10 次重试。就目前而言,此配置的理论最大值似乎总计大于 35:第 1 次初始执行 +(5 RetryAfters
+ 1 RetryNow
每次 RetryNow
尝试重复)
我是不是做错了什么?有没有推荐的方法来处理这种情况?我仍在努力了解策略配置,所以我假设我在这里缺少某种 recommended/best 实践。否则这似乎是一个重大疏忽,如果是这种情况,我肯定不会是唯一 运行 解决这个问题的人,但我在文档中找不到任何相关信息。
方案一:将两种重试策略合二为一
您可以在一项政策中处理这两种例外情况。您可以使用 .Or<>()
语法指定第二个异常,并使用 this overload 根据异常(和其他因素)选择重试前等待的持续时间:
AsyncRetryPolicy ApiPolicy = Policy
.Handle<HttpResponseException>(e => e.Response.StatusCode == HttpStatusCode.TooManyRequests)
.Or<HttpResponseException>(e => e.Response.StatusCode == HttpStatusCode.RequestTimeout)
.WaitAndRetryAsync(retryCount: maxAttempts,
sleepDurationProvider: (i, ex, ctx) =>
ex.Response.StatusCode == HttpStatusCode.TooManyRequests
? TimeSpan.FromSeconds(1)
: TimeSpan.Zero,
onRetryAsync: (ex, span, i, ctx) => /* whatever you have for logging */
);
此重试政策将限制为 1 + maxAttempts
次总体尝试,并反映您原始配置中的重试延迟。
解决方案 2:控制整体执行时间以抑制 'excessive' 重试
或者,如果您发现将两次重试表示为单独的策略(即原始的 RetryAfter
和 RetryNow
)更清楚,那么另一种选择是包装一个 [=17= 】 在他们之外。
TimeoutPolicy
将限制组合执行的总持续时间 - 包括所有尝试和重试之间的等待 - 提供一种基于时间的方法来防止组合重试意外增加。
// RetryAfter and RetryNow exactly as in your question. Then:
AsyncTimeoutPolicy OverallTimeout = Policy.TimeoutAsync(TimeSpan.FromSeconds(45));
IAsyncPolicy ApiPolicy = Policy.WrapAsync(OverallTimeout, RetryNow, RetryAfter);
如果你想要每次尝试超时,你也可以在 PolicyWrap 的内端引入它。
AsyncTimeoutPolicy OverallTimeout = Policy.TimeoutAsync(TimeSpan.FromSeconds(45));
AsyncTimeoutPolicy TimeoutPerTry = Policy.TimeoutAsync(TimeSpan.FromSeconds(10));
IAsyncPolicy ApiPolicy = Policy.WrapAsync(OverallTimeout, RetryNow, RetryAfter, TimeoutPerTry);