中止WaitAndRetryAsync策略?

时间:2018-06-28 19:40:31

标签: azure-cosmosdb polly

我想使用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中处理的“例外”。

有没有更好的方法来解决这个问题?

谢谢

-约翰

1 个答案:

答案 0 :(得分:0)

下面的第一个示例将重试之间的总等待时间限制为总时间跨度myWaitLimit,但没有考虑到在返回DocumentClientException之前对CosmosDB的调用花费了多长时间。因为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(如上例所示),则可以传递Context使用Polly CancellationToken作为described in this blog post


或者,Polly提供了TimeoutPolicy。使用PolicyWrap可以将其包装在重试策略之外。然后,无论是否发生429,都可以对整个执行施加超时。

如果该策略旨在管理本质上不占用TimeoutStrategy.Pessimistic的Cosmos DB异步调用,则要在以下时间强制超时,则需要使用TimeoutStrategy.Pessimistic该时间间隔。但是,请从Wiki中注意Dim Tbl As Table, TblCell As Cell, Rng As Range For Each Tbl In ActiveDocument.Tables For Each TblCell In Tbl.Range.Cells Set Rng = TblCell.Range With Rng .End = .End - 1 Do While .Characters.Last = vbCr .Characters.Last = vbNullString Loop End With Next Next 的工作方式:它允许调用线程离开无法取消的调用,但不会单方面取消无法取消的调用。该调用可能稍后出现故障,或者继续完成。


很明显,根据您的情况,考虑上述选项中的最佳选择。