Ham*_*med 1 c# timeout dotnet-httpclient .net-core polly
注册服务:
var host = new HostBuilder().ConfigureServices(services =>
{
services.AddHttpClient<Downloader>(client =>
{
client.Timeout = TimeSpan.FromSeconds(1); // -- T1
})
.AddPolicyHandler(HttpPolicyExtensions
.HandleTransientHttpError()
.Or<HttpRequestException>()
.WaitAndRetryAsync(Backoff.DecorrelatedJitterBackoffV2(
TimeSpan.FromSeconds(5), // -- T2
retryCount: 3)))
.AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(10)) // -- T3
.AddPolicyHandler(HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30))); // -- T4
services.AddTransient<Downloader>();
}).Build();
Run Code Online (Sandbox Code Playgroud)
实施Downloader:
class Downloader
{
private HttpClient _client;
public Downloader(IHttpClientFactory factory)
{
_client = factory.CreateClient();
}
public void Download(List<Uri> links)
{
await Parallel.ForEachAsync(
links,
async (link, _cancelationToken) =>
{
await _client.GetStreamAsync(uri, _cancellationToken);
});
}
}
Run Code Online (Sandbox Code Playgroud)
在此伪代码中,我对超时之间的相关性以及如何/何时重新提交 HTTP 请求感到困惑。具体来说:
T1、T2、T3、 和是如何T4“精心策划”的?我假设如果端点在 中没有响应T1,await _client.GetStreamAsync抛出超时异常,那么在与 相关的时间间隔内T2,HTTP 请求将被提交最大3次数,或者如果断路器计时器达到T4。那么 的作用是什么呢T3?
所有配置是否都与客户端相关HttpMessageHandler,并且我仍然需要将调用包装GetStreamAsync为如下?!
Policy
.Handle<Exception>()
.RetryAsync(3)
.ExecuteAsync(
async () => await _client.GetStreamAsync(uri, _cancellationToken));
Run Code Online (Sandbox Code Playgroud)
首先让我提供一些建议,然后讨论您的问题。
Wrap多个AddPolicyHandlers寄存器AddPolicyHandleraPolicyHttpMessageHandler是 a DelegatingHandler。在您的情况下,您有 3DelegatingHandler秒,因此异常传播是由 ASP.NET Core 而不是 Polly 完成的。
如果您愿意Policy.WrapAsync,您可以以 Polly 方式链接策略(升级)。
var T2 = HttpPolicyExtensions
.HandleTransientHttpError()
.Or<HttpRequestException>()
.WaitAndRetryAsync(Backoff.DecorrelatedJitterBackoffV2(
TimeSpan.FromSeconds(5),
retryCount: 3));
var T3 = Policy.TimeoutAsync<HttpResponseMessage>(10);
var T4 = HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
Run Code Online (Sandbox Code Playgroud)
var resilienceStrategy = Policy.WrapAsync<HttpResponseMessage>(T2, T3, T4);
var host = new HostBuilder().ConfigureServices(services =>
{
services
.AddHttpClient<Downloader>(client =>
client.Timeout = TimeSpan.FromSeconds(1))
.AddPolicyHandler(resilienceStrategy);
services.AddTransient<Downloader>();
}).Build();
Run Code Online (Sandbox Code Playgroud)
顺便说一下,交换超时和断路器策略可能是有意义的。如果超时是最内部的,并且您将调整断路器策略以了解超时问题 ( .Or<TimeoutRejectedException>()),那么它也可能会因此而中断。
var T3 = Policy.TimeoutAsync<HttpResponseMessage>(10);
var T4 = HttpPolicyExtensions
.HandleTransientHttpError()
.Or<TimeoutRejectedException>()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
var resilienceStrategy = Policy.WrapAsync<HttpResponseMessage>(T2, T4, T3);
Run Code Online (Sandbox Code Playgroud)
在超时或断路的情况下执行重试也可能有意义
var T2 = HttpPolicyExtensions
.HandleTransientHttpError()
.Or<HttpRequestException>()
.Or<TimeoutRejectedException>()
.Or<BrokenCircuitException>()
.WaitAndRetryAsync(Backoff.DecorrelatedJitterBackoffV2(
TimeSpan.FromSeconds(5),
retryCount: 3));
Run Code Online (Sandbox Code Playgroud)
请允许我从你的第二个问题开始。
所有配置都与客户端和 HttpMessageHandler 相关吗,我仍然需要将调用包装
GetStreamAsync为如下?!
不,你不需要这样做。由于您已经HttpClient用弹性策略装饰了您的策略,因此您不需要对每个HttpClient方法调用执行相同的操作。
请允许我将其分成多个问题
T1、T2、T3、T4是如何“编排”的?
HttpClients Timeout) 充当全局超时。这意味着如果您需要执行多次重试,那么它们将在 1 秒后被取消。因此,这是所有尝试的总体时间限制。
medianFirstRetryDelay)以带有抖动的指数退避方式提供重试之间的睡眠持续时间序列。换句话说,每次重试之间不是总是等待相同的时间,而是每次等待的时间越来越长。
HttpClient这是全局Timeout超时的对比Policy.WrapAsync),那么它也充当全局策略breakDuration)充当看门人。如果 CB 损坏(在您的情况下连续 5 次失败后),那么它会将自身转换为“打开”状态。
BrokenCircuitException当 CB 处于打开状态时,任何请求都会终止breakDuration一段时间后,它会转换为HalfOpen状态并允许单个探测。如果成功则 CB 返回Closed状态,否则返回Open我假设如果端点在 T1 内没有响应,await _client.GetStreamAsync 会抛出超时异常,然后在与 T2 相关的时间间隔内,HTTP 请求将最多提交 3 次,或者如果断路器计时器达到 T4。那么T3的作用是什么?
通过上一点,我想我已经解决了这个问题:)。因为您已将全局超时设置为 1 秒,所以您的本地超时(10 秒)永远不会触发。
如果您为全局超时设置更高的值,则可能会触发每个请求(基于重试尝试)超时。
如果上述任何一点不清楚,请告诉我,我将链接我之前的一些帖子,其中详细讨论了这一点。
更新#1
您能详细说明一下 T1 与 T3 吗?
在以下主题中,我尝试阐明全局超时和本地超时之间的区别:
最后,这是一个 SO 主题,其中介绍了如何拥有比 HttpClient 的 Timeout 更长的 Timeout。
我应该实现捕获 CB 的 Open、HalfOpen 和 Closed 状态并缓冲和保留状态请求的逻辑,还是 CB 在适当的时候在内部缓冲并重新提交请求?
断路器不是这样工作的。断路器不维护请求队列之类的东西。它只是一个代理,如果下游系统被视为暂时不可用,它可以缩短请求的执行。CB 本身不执行任何重试逻辑。
速率限制器策略也以同样的方式工作。在有足够的吞吐量之前,它不会保留请求。
您可以做的是创建 CB 感知重试逻辑并将它们组合起来
| 归档时间: |
|
| 查看次数: |
2687 次 |
| 最近记录: |