我希望实现与内置RateLimit政策 (即记录器消息)中的策略相同的行为,并读取重试后的标题,并等待等待所需的准确秒数,但使用内置的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;
});
}发布于 2022-05-30 07:27:39
有很多问题,所以让我回答所有的问题。
1)如何将记录器注入到策略中?
为此,您需要使用波莉语境。
上下文是在策略之外创建的。它用作容器来存储任意信息。
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;
});然后,在retry的sleepDurationProvider委托内的客户端,如果response是DelegateResult<HttpResponseMessage>,则可以像这样检索该值
response.Result.Headers.RetryAfter.Delta ?? TimeSpan.FromSeconds(0)https://stackoverflow.com/questions/72405752
复制相似问题