我想使用內置的RateLimit 策略實作與以下策略相同的行為,即記錄器訊息并讀取 Retry-After 標頭并等待需要等待的確切秒數,但使用內置的 RateLimit 策略.
試圖
// TODO: No logger message and not sure if it waits the time taken from the Retry-After header.
public static AsyncRateLimitPolicy Limit<T>(ILogger<T> logger)
{
return Policy.RateLimitAsync(RateLimitRetryCount, TimeSpan.FromSeconds(5));
}
作品
public static AsyncRetryPolicy<RestResponse> AsyncRateLimit<T>(ILogger<T> logger)
{
return Policy.HandleResult<RestResponse>(response => response.StatusCode == HttpStatusCode.TooManyRequests)
.WaitAndRetryAsync(RateLimitRetryCount,
(attemptCount, restResponse, _) =>
{
var retryAfterHeader = restResponse?.Result?.Headers?.SingleOrDefault(h => h.Name == "Retry-After");
double secondsInterval = 0;
if (retryAfterHeader != null)
{
var value = retryAfterHeader.Value?.ToString();
if (!double.TryParse(value, out secondsInterval))
{
secondsInterval = Math.Pow(2, attemptCount);
}
}
return TimeSpan.FromSeconds(secondsInterval);
},
(response, timeSpan, retryCount, _) =>
{
logger.LogTrace(
"The API request has been rate limited. HttpStatusCode={StatusCode}. Waiting {Seconds} seconds before retry. Number attempt {RetryCount}. Uri={Url}; RequestResponse={Content}",
response.Result.StatusCode, timeSpan.TotalSeconds, retryCount, response.Result.ResponseUri, response.Result.Content);
return Task.CompletedTask;
});
}
uj5u.com熱心網友回復:
有很多問題,所以讓我回答所有問題。
1)如何將記錄器注入策略?
為此,您需要使用Polly 的背景關系。
背景關系是在策略之外創建的。它用作存盤任意資訊的容器
var context = new Context().WithLogger(logger);
然后通過Execute/ExecuteAsync呼叫
await policy.ExecuteAsync(ctx => FooAsync(), context);
最后,您可以在任何用戶委托(如onRetry/ onRetryAsync)中使用背景關系來檢索傳遞的物件
(exception, timeSpan, retryCount, context) =>
{
var logger = context.GetLogger();
logger?.LogWarning(...);
...
}
和WithLogger擴展GetLogger方法
public static class ContextExtensions
{
private static readonly string LoggerKey = "LoggerKey";
public static Context WithLogger(this Context context, ILogger logger)
{
context[LoggerKey] = logger;
return context;
}
public static ILogger GetLogger(this Context context)
{
if (context.TryGetValue(LoggerKey, out object logger))
{
return logger as ILogger;
}
return null;
}
}
2)上述限速器的作業方式與重試相同嗎?
不會。速率限制器是一種主動策略,可用于防止資源濫用。RateLimitRejectedException這意味著如果超出預定義的限制,它將拋出一個。
每當我們談論彈性策略時,我們指的是兩方之間的預定義協議,以克服瞬時故障。所以速率限制器是這個故事的服務器端,而重試(反應策略)是客戶端。
如果您想RetryAfter在速率限制器中設定標題,那么您可以這樣做
IAsyncPolicy<HttpResponseMessage> limit = Policy
.RateLimitAsync(RateLimitRetryCount, TimeSpan.FromSeconds(5), RateLimitRetryCount,
(retryAfter, context) => {
var response = new HttpResponseMessage(System.Net.HttpStatusCode.TooManyRequests);
response.Headers.Add("Retry-After", retryAfter.TotalSeconds.ToString());
return response;
});
然后在重試sleepDurationProvider委托中的客戶端,如果response是DelegateResult<HttpResponseMessage>
response.Result.Headers.RetryAfter.Delta ?? TimeSpan.FromSeconds(0)
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/482868.html
