使用 Polly 重试处理较长时间间隔的 HTTP 请求错误是否安全
Is it safe to use Polly retry to handle HTTP request errors for longer time intervals
我正在尝试为我的应用程序实现我自己的 WebHooks 版本。当用户注册他们的 URL 挂钩时(假设它是错误的 URL 或不会用 2XX 代码响应),我想在自定义指数间隔内最多重试五次,比如 5 分钟、30 分钟、 2 小时、4 小时和 16 小时。我已经使用 .NET Polly 库实现了这个。
我的问题是,
1) 在最坏的情况下,第 5 次重试延长至 16 小时是否安全?
2) 它是线程安全的吗(Polly 说只要我的代码是线程安全的,它就是线程安全的)但我担心的是 16 小时长的间隔。
3) 假设 10 个请求失败,所有请求都在各自的时间间隔内重试。因此,越来越多的请求在一段时间后失败,我的服务器线程池是否会变满并且无法接受任何新请求?
4) 由于时间间隔很长,是否真的值得使用类似 Polly 的库或更好地使用 CRON 作业调度程序?
我的实现细节与 Polly 的官方示例非常相似或相同 IHttpClientFactory
(link).
感谢您的建议。
我强烈建议您深入研究 Polly 源代码,它相对容易阅读。
例如,如果您从 WaitAndRetryAsync
函数开始,您很快就会到达 AsyncRetryEngine
。这包含重试实现,这就是为什么它只是一个名为 ImplementationAsync
的方法。如果我们跳转到 wait related part 那么你会发现下面这段代码:
if (waitDuration > TimeSpan.Zero)
{
await SystemClock.SleepAsync(waitDuration, cancellationToken).ConfigureAwait(continueOnCapturedContext);
}
如果您查看 SystemClock
,您会发现 Sleep
和 SleepAsync
字段(方法)定义:
public static Func<TimeSpan, CancellationToken, Task> SleepAsync =
new Func<TimeSpan, CancellationToken, Task>(Task.Delay);
SystemClock.Sleep = (Action<TimeSpan, CancellationToken>) ((timeSpan, cancellationToken) =>
{
if (!cancellationToken.WaitHandle.WaitOne(timeSpan))
return;
cancellationToken.ThrowIfCancellationRequested();
});
如您所见,如果您调用 WaitAndRetryAsync
,那么您的策略将调用 Task.Delay
,这是非阻塞的。如果您调用 WaitAndRetry
,那么您的策略将调用 WaitHandle
的 WaitOne
,这是阻塞的。
因此,如果您长时间使用 WaitAndRetry,则会阻塞线程(除非它因某种原因终止)。在 WaitAndRetryAsync 的情况下,ThreadPool 将在延迟完成后收到有关完成的通知。
但我仍然建议使用 cron 作业来解决这类问题。
我正在尝试为我的应用程序实现我自己的 WebHooks 版本。当用户注册他们的 URL 挂钩时(假设它是错误的 URL 或不会用 2XX 代码响应),我想在自定义指数间隔内最多重试五次,比如 5 分钟、30 分钟、 2 小时、4 小时和 16 小时。我已经使用 .NET Polly 库实现了这个。
我的问题是,
1) 在最坏的情况下,第 5 次重试延长至 16 小时是否安全?
2) 它是线程安全的吗(Polly 说只要我的代码是线程安全的,它就是线程安全的)但我担心的是 16 小时长的间隔。
3) 假设 10 个请求失败,所有请求都在各自的时间间隔内重试。因此,越来越多的请求在一段时间后失败,我的服务器线程池是否会变满并且无法接受任何新请求?
4) 由于时间间隔很长,是否真的值得使用类似 Polly 的库或更好地使用 CRON 作业调度程序?
我的实现细节与 Polly 的官方示例非常相似或相同 IHttpClientFactory
(link).
感谢您的建议。
我强烈建议您深入研究 Polly 源代码,它相对容易阅读。
例如,如果您从 WaitAndRetryAsync
函数开始,您很快就会到达 AsyncRetryEngine
。这包含重试实现,这就是为什么它只是一个名为 ImplementationAsync
的方法。如果我们跳转到 wait related part 那么你会发现下面这段代码:
if (waitDuration > TimeSpan.Zero)
{
await SystemClock.SleepAsync(waitDuration, cancellationToken).ConfigureAwait(continueOnCapturedContext);
}
如果您查看 SystemClock
,您会发现 Sleep
和 SleepAsync
字段(方法)定义:
public static Func<TimeSpan, CancellationToken, Task> SleepAsync =
new Func<TimeSpan, CancellationToken, Task>(Task.Delay);
SystemClock.Sleep = (Action<TimeSpan, CancellationToken>) ((timeSpan, cancellationToken) =>
{
if (!cancellationToken.WaitHandle.WaitOne(timeSpan))
return;
cancellationToken.ThrowIfCancellationRequested();
});
如您所见,如果您调用 WaitAndRetryAsync
,那么您的策略将调用 Task.Delay
,这是非阻塞的。如果您调用 WaitAndRetry
,那么您的策略将调用 WaitHandle
的 WaitOne
,这是阻塞的。
因此,如果您长时间使用 WaitAndRetry,则会阻塞线程(除非它因某种原因终止)。在 WaitAndRetryAsync 的情况下,ThreadPool 将在延迟完成后收到有关完成的通知。
但我仍然建议使用 cron 作业来解决这类问题。