我想了解如何使用HttpClientFactory
实现Polly的乐观超时策略。
在网络上的示例中,当调用异步方法以传递取消令牌时,会使用超时策略。但是,如果我从配置服务中设置超时策略,如指南中所示(,我该如何管理取消令牌?
在示例代码中,从链接的指南中,我看到的是:
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(10); // Timeout for an individual try
serviceCollection.AddHttpClient("GitHub", client =>
{
client.BaseAddress = new Uri("https://api.github.com/");
client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
client.Timeout = TimeSpan.FromSeconds(60); // Overall timeout across all tries
})
.AddPolicyHandler(retryPolicy)
.AddPolicyHandler(timeoutPolicy);
您应该将重试和超时策略链接到一个组合策略中。
你有两个选择:
Wrap
方法
.AddPolicyHandler(retryPolicy.Wrap(timeoutPolicy))
timeoutPolicy
是内部策略,因此它分别应用于每次尝试retryPolicy
是外部策略,因此它是最重要的超时策略- 注意订购事项(我将在后面的部分中详细说明(
PolicyWrap
类
.AddPolicyHandler(Policy.Wrap(retryPolicy,timeoutPolicy))
- 第一个论点是最外层的政策
- 最后一个论点是最内在的政策
订购很重要
您应该意识到以下两种组合策略非常不同:
Policy.Wrap(retryPolicy,timeoutPolicy)
Policy.Wrap(timeoutPolicy, retryPolicy)
- 在第一种情况下,您有一个本地超时,该超时适用于每次重试
- 在第二种情况下,您有一个全局超时,它适用于整个重试活动
推进这一想法,您可以通过定义全局超时来避免设置HttpClient的Timeout
属性:
var localTimeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(10);
var globalTimeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(60);
var resilientStrategy = Policy.Wrap(globalTimeoutPolicy, retryPolicy, localTimeoutPolicy);
serviceCollection.AddHttpClient("GitHub", client =>
{
client.BaseAddress = new Uri("https://api.github.com/");
client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
})
.AddPolicyHandler(resilientStrategy);
更新#1乐观超时
Polly的Timeout同时支持乐观和悲观超时。换句话说,Polly可以尝试取消那些预测CancellationToken
(乐观(的待包装方法以及那些不预测(悲观(的方法。默认为前者。
在乐观的情况下,你有两个选择:
- 让策略取消
await policy.ExecuteAsync(
async ct => await httpClient.SendAsync(..., ct),
CancellationToken.None);
- 或者将其与您的自定义CTS组合/链接
await policy.ExecuteAsync(
async ct => await httpClient.SendAsync(..., ct),
cancellationSource.Token);
如果在启动过程中注册了命名/键入的客户端,则只能使用第一个选项。由于policy.ExecuteAsync
将代表您(隐含地(调用。
如果您注册了一个类型化客户端,并在该客户端中定义了策略,那么您就是在显式调用ExecuteAsync
,在这里您可以决定使用哪个版本。