【发布时间】:2019-12-04 12:36:34
【问题描述】:
我正在使用 polly 对 HTTP POST 请求进行简单的 n 次重试。它应该处理任何异常并重试将我的有效负载发布到 api 端点 n 次。因此,我使用 WaitAndRetryPolicy 包装 TimoutPolicy 和悲观策略,每次尝试超时。两者都是异步策略。
当重试案例发生时,每一次重试尝试都会在重新建立连接后发布到端点。
包装这两个策略的方法:
public static PolicyWrap WaitAndRetryNTimesWithTimeoutPerTry(int n, TimeSpan sleepDuration, TimeSpan retryTimeout)
{
var waitAndRetryPolicy = Policy.Handle<Exception>().WaitAndRetryAsync(
retryCount: n,
sleepDurationProvider: attempt => sleepDuration,
onRetry: (exception, waitDuration, ctx) =>
{
Debug.WriteLine($"[Polly.OnRetry due '{exception.Message}'; waiting for {waitDuration.TotalMilliseconds} ms before retrying.");
}
);
var timeoutPerTryPolicy = Policy.TimeoutAsync(
retryTimeout, TimeoutStrategy.Pessimistic);
return waitAndRetryPolicy.WrapAsync(timeoutPerTryPolicy);
}
调用web api的代码:
var waitAndRetry5TimesWithShortTimeout = ResiliencePolicyFactory.WaitAndRetryNTimesWithTimeoutPerTry(
n: 5,
sleepDuration: TimeSpan.FromMilliseconds(700),
retryTimeout: TimeSpan.FromMilliseconds(2300));
}
try
{
await waitAndRetry5TimesWithShortTimeout.ExecuteAndCaptureAsync(async token =>
{
if (!cancellationToken.IsCancellationRequested)
{
response = await client.PostAsync(uri, content, cancellationToken);
if (response.IsSuccessStatusCode)
{
Debug.WriteLine($"[{nameof(CheckinService)}] ===>> Now Checked in!");
}
}
}, cancellationToken);
}
catch(Exception ex)
{
throw new ApplicationException("NoCheckInPossible", ex);
}
当代码遇到重试情况并在多次重试后成功时,每次重试尝试都会发布到端点,尽管我将取消令牌传递给 ExecuteAsync-Task 和 HttpClient。
据我了解,第一个成功的请求应该取消所有挂起的重试。谁能指出我做错了什么?
【问题讨论】:
-
在
ExecuteAndCaptureAsync(...)内,使用Polly 在执行委托时将传入的令牌(在您的情况下为token),以便超时工作。在发布的代码中,该委托使用您自己的变量cancellationToken(我看不到是否有任何取消;当然超时不会)。如果这可以为您解决问题,我可以将其写为正确的答案。 -
另外:
TimeoutStrategy.Pessimistic设计用于执行委托不兑现取消令牌的情况。HttpClient确实尊重这些令牌,因此您应该能够使用更简单的TimeoutStrategy.Optimistic。 -
TimeoutStrategy.Pessimisticonly walks away from timed-out executions,这可能是您看到早期尝试继续完成的原因 - 您实际上并没有取消它们(可能是由于使用了错误的取消令牌;请参阅第一条评论),所以他们会如果在HttpClient自己的超时(默认值:30 秒)之前重新建立底层连接,也完成。
标签: polly