![](/img/trans.png)
[英]IHttpClient Polly Timeout and WaitAndRetry policy when handling concurrent http requests Clarification
[英]Polly.Contrib.WaitAndRetry to "funnel" all requests when hitting rate limit
我們使用 Polly 中的 Dropbox API 來處理重試。
我們將其設置為指數回退,就像這里解釋的那樣。
我們遇到的問題是我們進行了大量的並發調用。
當 API 開始拋出速率限制異常時,每個單獨的調用者都會退出,但新的調用者仍會調用 API 並“竊取”正在等待的調用者的重試。
這意味着在高負載時,我們會遇到失敗的 API 調用和錯誤。
我們想要實現的是,在速率限制錯誤時,對 API 的所有調用(包括新調用者)都會同步並等待速率限制到期。
然后可以恢復調用(理想情況下按順序確保調用不再返回速率限制異常)。
是否有 Polly 支持的方法來實現這一目標?
根據我的理解,您希望擁有以下內容:
RetryAfter
時間跨度讓我們整理一個工作示例
在這里,我們將實現一個超級簡單的模擬,可以模擬節流。
讓我們從異常開始
public class DownstreamServiceException: Exception
{
public TimeSpan RetryAfter { get; set; }
}
現在,讓我們看看服務代碼
public class DownstreamService
{
private readonly CancellationTokenSource initCompletionSignal;
private readonly TimeSpan initDuration;
private bool isAvailable = false;
private DateTime initEstimatedEnd;
public DownstreamService()
{
initDuration = TimeSpan.FromSeconds(10);
initCompletionSignal = new CancellationTokenSource(initDuration);
initCompletionSignal.Token.Register(() => isAvailable = true);
initEstimatedEnd = DateTime.UtcNow.Add(initDuration);
}
public Task<string> GetAsync()
{
if (!isAvailable) throw new DownstreamServiceException { RetryAfter = initEstimatedEnd - DateTime.UtcNow };
return Task.FromResult("Available");
}
}
CancellationTokenSource
作為計時器來使服務可用GetAsync
在不可用時被調用(我們被限制),它會返回異常,否則返回"Available"
字符串在這里,我們將定義一個斷路器來在下游不可用時縮短請求(我們被限制了)
var throttledPolicy = Policy<string>
.Handle<DownstreamServiceException>()
.CircuitBreakerAsync(1, TimeSpan.FromSeconds(0),
onBreak: (result, state, _, __) => {
if (state == CircuitState.Open) return;
Console.WriteLine("onBreak");
throw result.Exception;
},
onReset: (_) => Console.WriteLine("onReset"),
onHalfOpen: () => { });
DownstreamServiceException
時,Circuit Breaker 將從Closed轉換為OpenTimeSpan.FromSeconds(0)
)在這里無關緊要
if (state == CircuitState.Open)
:這將在重試部分解釋這是解決方案中最復雜的部分,因為此重試策略以不同的方式處理多個異常( DownstreamServiceException
、 IsolatedCircuitException
)
CancellationTokenSource throttlingEndSignal;
var retryPolicy = Policy<string>
.Handle<DownstreamServiceException>()
.Or<IsolatedCircuitException>()
.WaitAndRetryForeverAsync(_ => TimeSpan.FromSeconds(3),
onRetry: (dr, __) =>
{
Console.WriteLine($"onRetry caused by {dr.Exception.GetType().Name}");
if (dr.Exception is DownstreamServiceException dse)
{
throttledPolicy.Isolate();
throttlingEndSignal = new(dse.RetryAfter);
throttlingEndSignal.Token.Register(() => throttledPolicy.Reset());
}
});
DownstreamServiceException
開始
onBreak
委托重新拋出收到的異常onRetry
內部,我們有一個DownstreamServiceException
的保護表達式Isolate
,它試圖從打開狀態轉換到隔離狀態 >> 調用onBreak
委托if (state == CircuitState.Open) return;
那里的代碼CancellationTokenSource
執行相同的計時器技巧,當節流結束時,我們將斷路器推回關閉狀態( Reset
)IsolatedCircuitException
的情況要簡單得多
var combinedPolicy = Policy.WrapAsync(retryPolicy, throttledPolicy);
var result = await combinedPolicy.ExecuteAsync(async () => await service.GetAsync());
請注意以下事項:
我希望您發現這個小示例應用程序很有用 :)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.