【发布时间】:2022-10-02 04:57:53
【问题描述】:
我正在开发一个访问速率受限 API 的集成解决方案。我正在使用不同端点上的多个 HTTP 动词对 API 执行各种 CRUD 操作(尽管在同一台服务器上)。我曾多次提到波莉,但我还没有想出一个真正有效的解决方案。
这就是我在我的创业公司中所拥有的:
builder.Services
.AddHttpClient(\"APIClient\", client =>
{
client.BaseAddress = new Uri(C.Configuration.GetValue<string>(\"APIBaseAddress\"));
})
.AddTransientHttpErrorPolicy(builder =>
builder.WaitAndRetryAsync(new []
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(15),
}));
这只是在失败时重试的弹性。我在单例 ApiWrapper 类中有一个 RateLimit 策略:
public sealed class ApiWrapper
{
private static readonly Lazy<ApiWrapper> lazy = new Lazy<ApiWrapper>(() => new ApiWrapper());
public static ApiWrapper Instance { get { return lazy.Value; } }
private IHttpClientFactory _httpClientFactory;
public readonly AsyncRateLimitPolicy RateLimit = Policy.RateLimitAsync(150, TimeSpan.FromSeconds(10), 50); // 150 actions within 10 sec, 50 burst
private ApiWrapper()
{
}
public void SetFactory(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public HttpClient GetApiClient()
{
return _httpClientFactory.CreateClient(\"APIClient\");
}
}
该策略在多个其他类中使用,如下所示:
public class ApiConsumer
{
private HttpClient _httpClient = ApiWrapper.Instance.GetApiClient();
public async Task<bool> DoSomethingWithA(List<int> customerIDs)
{
foreach (int id in customerIDs)
{
HttpResponseMessage httpResponse = await ApiWrapper.Instance.RateLimit.ExecuteAsync(() => _httpClient.GetAsync($\"http://some.endpoint\"));
}
}
}
我的期望是速率限制器不会触发比配置更多的请求,但这似乎不是真的。据我了解,它的工作方式是,如果调用次数超过已配置的限制,速率限制器只会引发异常。这就是我认为重试策略会发挥作用的地方,所以如果它没有通过限制器,请在 5 或 15 秒后重试。
然后我玩了一下 Polly 的 Bulkhead 策略,但据我所知,这意味着限制并行执行的数量。
我有多个线程可能使用不同的 HttpClients(全部由工厂创建,如上例所示)具有不同的方法和端点,但都使用相同的策略。有些线程并行运行,有些是顺序运行的,因为我必须在发送下一个请求之前等待它们的响应。
关于如何通过 Polly 实现或应该实现这一点的任何建议? (或任何其他扩展,如果有充分的理由)
-
对于某些 API,当它们返回 429 Too Many Requests 时,响应包含一个参数,说明何时重试(以秒为单位或绝对时间)。所以基本上,API 会告诉你什么时候再试一次,而不是你再试一次然后立即被拒绝。
-
那不是波莉的工作。 Polly 用于恢复、重试和确保您不超过速率限制。但是,您将如何处理受限制的请求?你会拒绝他们吗?排队?这是一个重要的应用程序特性,而不是你可以从库中获得的东西
-
发出这些请求的代码呢?您是否允许它继续生成无法服务的请求,或者您是否使用背压机制告诉它减速?那是 Channels、Dataflow 库、
Parallel.ForEachAsync等的工作。 -
谢谢大家的提醒。假设 Polly 只会将这些请求排队并仅将它们一一发送以确保不达到速率限制,可能太简单了。 @Panagiotis:我假设我需要创建一个队列,一些机制来处理队列中的项目并将响应返回给请求线程。有没有你推荐看的扩展/框架?将看一下 Dataflow,但不确定它是否是我需要的,因为请求本身可以按顺序触发,不需要并行...(对不起,我对 C# 很陌生)
-
@Neil:我一开始不想得到 429 ......
标签: c# dotnet-httpclient rate-limiting polly resiliency