中止 WaitAndRetryAsync 策略?
Abort WaitAndRetryAsync policy?
我想使用 WaitAndRetryAsync
来帮助重试 http 429(节流)错误。重试延迟作为异常本身的 属性 返回。
但是如果总持续时间超过一定数量,我需要添加累计时间并放弃重试循环。
policy = Policy.Handle<DocumentClientException>(ex => ex.StatusCode == (HttpStatusCode)429)
.WaitAndRetryAsync(
retryCount: retries,
sleepDurationProvider: (retryCount, exception, context) => {
DocumentClientException dce = exception as DocumentClientException;
// Here I would like to check the total time and NOT return a RetryAfter value if my overall time is exceeded. Instead re-throw the 'exception'.
return dce.RetryAfter;
},
onRetryAsync: async (res, timespan, retryCount, context) => {
});
当超过总时间时,我想重新抛出在 sleepDurationProvider 中处理的 'exception'。
有没有更好的方法来处理这个问题?
谢谢
-约翰
下面的第一个示例将 重试之间的总等待时间 限制为总时间跨度 myWaitLimit
,但没有考虑对 CosmosDB 的调用在返回之前花费了多长时间 DocumentClientException
。因为 Polly Context
是执行范围的,所以这是线程安全的。类似于:
policy = Policy.Handle<DocumentClientException>(ex => ex.StatusCode == (HttpStatusCode)429)
.WaitAndRetryAsync(
retryCount: retries,
sleepDurationProvider: (retryCount, exception, context) => {
DocumentClientException dce = exception as DocumentClientException;
TimeSpan toWait = dce.RetryAfter;
TimeSpan waitedSoFar;
if (!Context.TryGetValue("WaitedSoFar", out waitedSoFar)) waitedSoFar = TimeSpan.Zero; // (probably some extra casting actually needed between object and TimeSpan, but this kind of idea ...)
waitedSoFar = waitedSoFar + toWait;
if (waitedSoFar > myWaitLimit)
throw dce; // or use ExceptionDispatchInfo to preserve stack trace
Context["WaitedSoFar"] = waitedSoFar; // (magic string "WaitedSoFar" only for readability; of course you can factor this out)
return toWait;
},
onRetryAsync: async (res, timespan, retryCount, context) => {
});
另一种方法可以使用超时 CancellationToken
来限制 整体 执行时间(当出现 429 秒时)。在发出 CancellationToken
信号后,下面的方法将不再重试。这种方法被建模为接近问题中请求的功能,但超时显然只有在返回 429 响应并调用 sleepDurationProvider
委托时才会生效。
CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(/* my timeout */);
var policy = Policy.Handle<DocumentClientException>(ex => ex.StatusCode == (HttpStatusCode)429)
.WaitAndRetryAsync(
retryCount: retries,
sleepDurationProvider: (retryCount, exception, context) => {
if (cts.IsCancellationRequested) throw exception; // or use ExceptionDispatchInfo to preserve stack trace
DocumentClientException dce = exception as DocumentClientException;
return dce.RetryAfter;
},
onRetryAsync: async (res, timespan, retryCount, context) => {
});
如果您不想在与使用它相同的范围内定义 policy
并关闭变量 cts
(如上例所示),您可以传递 CancellationTokenSource
将 Polly Context
用作 described in this blog post.
或者,Polly 提供了一个 TimeoutPolicy
. Using PolicyWrap
您可以将其包装在重试策略之外。然后无论是否出现 429,都可以对整个执行施加超时。
如果该策略旨在管理本质上不采用 CancellationToken
的 Cosmos DB 异步调用,则需要使用 TimeoutStrategy.Pessimistic
如果您想 enforce 在那个时间间隔超时。但是,请注意 wiki TimeoutStrategy.Pessimistic
的操作方式:它允许调用线程离开不可取消的调用,但不会单方面取消不可取消的调用。该调用可能稍后出错,或继续完成。
显然,请根据您的情况考虑上述选项中最好的选项。
我想使用 WaitAndRetryAsync
来帮助重试 http 429(节流)错误。重试延迟作为异常本身的 属性 返回。
但是如果总持续时间超过一定数量,我需要添加累计时间并放弃重试循环。
policy = Policy.Handle<DocumentClientException>(ex => ex.StatusCode == (HttpStatusCode)429)
.WaitAndRetryAsync(
retryCount: retries,
sleepDurationProvider: (retryCount, exception, context) => {
DocumentClientException dce = exception as DocumentClientException;
// Here I would like to check the total time and NOT return a RetryAfter value if my overall time is exceeded. Instead re-throw the 'exception'.
return dce.RetryAfter;
},
onRetryAsync: async (res, timespan, retryCount, context) => {
});
当超过总时间时,我想重新抛出在 sleepDurationProvider 中处理的 'exception'。
有没有更好的方法来处理这个问题?
谢谢
-约翰
下面的第一个示例将 重试之间的总等待时间 限制为总时间跨度 myWaitLimit
,但没有考虑对 CosmosDB 的调用在返回之前花费了多长时间 DocumentClientException
。因为 Polly Context
是执行范围的,所以这是线程安全的。类似于:
policy = Policy.Handle<DocumentClientException>(ex => ex.StatusCode == (HttpStatusCode)429)
.WaitAndRetryAsync(
retryCount: retries,
sleepDurationProvider: (retryCount, exception, context) => {
DocumentClientException dce = exception as DocumentClientException;
TimeSpan toWait = dce.RetryAfter;
TimeSpan waitedSoFar;
if (!Context.TryGetValue("WaitedSoFar", out waitedSoFar)) waitedSoFar = TimeSpan.Zero; // (probably some extra casting actually needed between object and TimeSpan, but this kind of idea ...)
waitedSoFar = waitedSoFar + toWait;
if (waitedSoFar > myWaitLimit)
throw dce; // or use ExceptionDispatchInfo to preserve stack trace
Context["WaitedSoFar"] = waitedSoFar; // (magic string "WaitedSoFar" only for readability; of course you can factor this out)
return toWait;
},
onRetryAsync: async (res, timespan, retryCount, context) => {
});
另一种方法可以使用超时 CancellationToken
来限制 整体 执行时间(当出现 429 秒时)。在发出 CancellationToken
信号后,下面的方法将不再重试。这种方法被建模为接近问题中请求的功能,但超时显然只有在返回 429 响应并调用 sleepDurationProvider
委托时才会生效。
CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(/* my timeout */);
var policy = Policy.Handle<DocumentClientException>(ex => ex.StatusCode == (HttpStatusCode)429)
.WaitAndRetryAsync(
retryCount: retries,
sleepDurationProvider: (retryCount, exception, context) => {
if (cts.IsCancellationRequested) throw exception; // or use ExceptionDispatchInfo to preserve stack trace
DocumentClientException dce = exception as DocumentClientException;
return dce.RetryAfter;
},
onRetryAsync: async (res, timespan, retryCount, context) => {
});
如果您不想在与使用它相同的范围内定义 policy
并关闭变量 cts
(如上例所示),您可以传递 CancellationTokenSource
将 Polly Context
用作 described in this blog post.
或者,Polly 提供了一个 TimeoutPolicy
. Using PolicyWrap
您可以将其包装在重试策略之外。然后无论是否出现 429,都可以对整个执行施加超时。
如果该策略旨在管理本质上不采用 CancellationToken
的 Cosmos DB 异步调用,则需要使用 TimeoutStrategy.Pessimistic
如果您想 enforce 在那个时间间隔超时。但是,请注意 wiki TimeoutStrategy.Pessimistic
的操作方式:它允许调用线程离开不可取消的调用,但不会单方面取消不可取消的调用。该调用可能稍后出错,或继续完成。
显然,请根据您的情况考虑上述选项中最好的选项。