Polly 和多个 HttpClients
Polly and Multiple HttpClients
我想将 Polly 与我的 HttpClientFactory 结合使用(在我的 C# .NET 5.0 项目中)。
但我遇到的问题是我的工厂中有多个命名的 HttpClients,而我想要实现的是当我有一个特定的状态代码时,例如404 我想使用我工厂的 另一个名为 HttpClient 的 重试(指向不同的服务器)。
但我看到人们经常使用 services.AddHttpClient(name, configureOptions).AddPolicyHandler()
模式。但那是行不通的,因为那不会调用另一个命名的 HttpClient。
我还想在 408 发生时“为他们自己”重试两个客户端。
是否有任何模式或示例代码?
我不知道最好的前进方向是什么。
我认为您可以通过以下方式实现所需的行为。
让我们注册两个命名的 http 客户端,在出现 408 状态代码时重试:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("ServiceA")
.AddPolicyHandler(GetRetryPolicy("ServiceA"));
services.AddHttpClient("ServiceB")
.AddPolicyHandler(GetRetryPolicy("ServiceB"));
//...
}
private IAsyncPolicy<HttpResponseMessage> GetRetryPolicy(string name)
=> Policy<HttpResponseMessage>
.HandleResult(res => res.StatusCode == System.Net.HttpStatusCode.RequestTimeout)
.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(200),
onRetryAsync: (dr, ts) => { Console.WriteLine($"Retry by {name}"); return Task.CompletedTask; });
我提供了一个 onRetryAsync
用于调试目的,只是为了查看重试何时执行。
现在让我们用一个简单的 webapi 控制器来连接东西:
[Route("api/[controller]")]
public class HomeController : Controller
{
private readonly IHttpClientFactory clientFactory;
public HomeController(IHttpClientFactory clientFactory)
{
this.clientFactory = clientFactory;
}
[HttpGet]
public async Task<IActionResult> Get(int expectedStatusCode)
{
var result = await GetAsync(GetPrimaryProxy(), expectedStatusCode);
if(result != null && result.StatusCode == System.Net.HttpStatusCode.NotFound)
result = await GetAsync(GetSecondaryProxy(), expectedStatusCode);
return StatusCode(500, result);
}
private HttpClient GetPrimaryProxy() => clientFactory.CreateClient("ServiceA");
private HttpClient GetSecondaryProxy() => clientFactory.CreateClient("ServiceB");
private async Task<HttpResponseMessage> GetAsync(HttpClient client, int expectedStatusCode)
=> await client.GetAsync($"https://httpstat.us/{expectedStatusCode}");
}
- 我已经使用
https://httpstat.us
网站来模拟预期的响应状态代码
- 很遗憾,您必须手动进行故障转移。无法以检查
HttpResponseMessage
和 returns 和 HttpClient
. 的方式设置回退策略
/api/Home/404
调试日志:
System.Net.Http.HttpClient.ServiceA.LogicalHandler: Information: Start processing HTTP request GET https://httpstat.us/404
info: System.Net.Http.HttpClient.ServiceA.LogicalHandler[100]
Start processing HTTP request GET https://httpstat.us/404
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[100]
Sending HTTP request GET https://httpstat.us/404
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Sending HTTP request GET https://httpstat.us/404
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[101]
Received HTTP response headers after 319.9439ms - 404
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Received HTTP response headers after 319.9439ms - 404
info: System.Net.Http.HttpClient.ServiceA.LogicalHandler[101]
End processing HTTP request after 326.1409ms - 404
System.Net.Http.HttpClient.ServiceA.LogicalHandler: Information: End processing HTTP request after 326.1409ms - 404
info: System.Net.Http.HttpClient.ServiceB.LogicalHandler[100]
Start processing HTTP request GET https://httpstat.us/404
System.Net.Http.HttpClient.ServiceB.LogicalHandler: Information: Start processing HTTP request GET https://httpstat.us/404
info: System.Net.Http.HttpClient.ServiceB.ClientHandler[100]
Sending HTTP request GET https://httpstat.us/404
System.Net.Http.HttpClient.ServiceB.ClientHandler: Information: Sending HTTP request GET https://httpstat.us/404
info: System.Net.Http.HttpClient.ServiceB.ClientHandler[101]
Received HTTP response headers after 344.5937ms - 404
System.Net.Http.HttpClient.ServiceB.ClientHandler: Information: Received HTTP response headers after 344.5937ms - 404
info: System.Net.Http.HttpClient.ServiceB.LogicalHandler[101]
End processing HTTP request after 350.932ms - 404
System.Net.Http.HttpClient.ServiceB.LogicalHandler: Information: End processing HTTP request after 350.932ms - 404
ServiceA
发出请求,收到404
Retry
未触发,因为仅处理 408
ServiceB
发出请求,收到404
Retry
未触发,因为仅处理 408
/api/Home/408
调试日志:
info: System.Net.Http.HttpClient.ServiceA.LogicalHandler[100]
Start processing HTTP request GET https://httpstat.us/408
System.Net.Http.HttpClient.ServiceA.LogicalHandler: Information: Start processing HTTP request GET https://httpstat.us/408
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[100]
Sending HTTP request GET https://httpstat.us/408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Sending HTTP request GET https://httpstat.us/408
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[101]
Received HTTP response headers after 343.5167ms - 408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Received HTTP response headers after 343.5167ms - 408
Retry by ServiceA
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[100]
Sending HTTP request GET https://httpstat.us/408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Sending HTTP request GET https://httpstat.us/408
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[101]
Received HTTP response headers after 236.9796ms - 408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Received HTTP response headers after 236.9796ms - 408
Retry by ServiceA
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[100]
Sending HTTP request GET https://httpstat.us/408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Sending HTTP request GET https://httpstat.us/408
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[101]
Received HTTP response headers after 207.2602ms - 408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Received HTTP response headers after 207.2602ms - 408
Retry by ServiceA
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[100]
Sending HTTP request GET https://httpstat.us/408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Sending HTTP request GET https://httpstat.us/408
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[101]
Received HTTP response headers after 203.3911ms - 408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Received HTTP response headers after 203.3911ms - 408
System.Net.Http.HttpClient.ServiceA.LogicalHandler: Information: End processing HTTP request after 1618.0826ms - 408
info: System.Net.Http.HttpClient.ServiceA.LogicalHandler[101]
End processing HTTP request after 1618.0826ms - 408
ServiceA
发出请求,收到408
Retry
在 200 毫秒延迟后触发
ServiceA
发出请求,收到408
Retry
在 200 毫秒延迟后触发
ServiceA
发出请求,收到408
Retry
在 200 毫秒延迟后触发
ServiceA
发出请求,收到408
Retry
未触发,因为超过了最大重试次数
ServiceB
未被调用,因为状态代码是 408 而不是 404
我最终没有使用 PollyHttpClientBuilderExtensions.AddPolicyHandler
但我用它作为灵感来编写我自己的:https://github.com/App-vNext/Polly-Samples/blob/master/PollyDemos/Async/AsyncDemo08_Wrap-Fallback-WaitAndRetry-CircuitBreaker.cs
我想将 Polly 与我的 HttpClientFactory 结合使用(在我的 C# .NET 5.0 项目中)。
但我遇到的问题是我的工厂中有多个命名的 HttpClients,而我想要实现的是当我有一个特定的状态代码时,例如404 我想使用我工厂的 另一个名为 HttpClient 的 重试(指向不同的服务器)。
但我看到人们经常使用 services.AddHttpClient(name, configureOptions).AddPolicyHandler()
模式。但那是行不通的,因为那不会调用另一个命名的 HttpClient。
我还想在 408 发生时“为他们自己”重试两个客户端。
是否有任何模式或示例代码? 我不知道最好的前进方向是什么。
我认为您可以通过以下方式实现所需的行为。
让我们注册两个命名的 http 客户端,在出现 408 状态代码时重试:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("ServiceA")
.AddPolicyHandler(GetRetryPolicy("ServiceA"));
services.AddHttpClient("ServiceB")
.AddPolicyHandler(GetRetryPolicy("ServiceB"));
//...
}
private IAsyncPolicy<HttpResponseMessage> GetRetryPolicy(string name)
=> Policy<HttpResponseMessage>
.HandleResult(res => res.StatusCode == System.Net.HttpStatusCode.RequestTimeout)
.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(200),
onRetryAsync: (dr, ts) => { Console.WriteLine($"Retry by {name}"); return Task.CompletedTask; });
我提供了一个 onRetryAsync
用于调试目的,只是为了查看重试何时执行。
现在让我们用一个简单的 webapi 控制器来连接东西:
[Route("api/[controller]")]
public class HomeController : Controller
{
private readonly IHttpClientFactory clientFactory;
public HomeController(IHttpClientFactory clientFactory)
{
this.clientFactory = clientFactory;
}
[HttpGet]
public async Task<IActionResult> Get(int expectedStatusCode)
{
var result = await GetAsync(GetPrimaryProxy(), expectedStatusCode);
if(result != null && result.StatusCode == System.Net.HttpStatusCode.NotFound)
result = await GetAsync(GetSecondaryProxy(), expectedStatusCode);
return StatusCode(500, result);
}
private HttpClient GetPrimaryProxy() => clientFactory.CreateClient("ServiceA");
private HttpClient GetSecondaryProxy() => clientFactory.CreateClient("ServiceB");
private async Task<HttpResponseMessage> GetAsync(HttpClient client, int expectedStatusCode)
=> await client.GetAsync($"https://httpstat.us/{expectedStatusCode}");
}
- 我已经使用
https://httpstat.us
网站来模拟预期的响应状态代码 - 很遗憾,您必须手动进行故障转移。无法以检查
HttpResponseMessage
和 returns 和HttpClient
. 的方式设置回退策略
/api/Home/404
调试日志:
System.Net.Http.HttpClient.ServiceA.LogicalHandler: Information: Start processing HTTP request GET https://httpstat.us/404
info: System.Net.Http.HttpClient.ServiceA.LogicalHandler[100]
Start processing HTTP request GET https://httpstat.us/404
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[100]
Sending HTTP request GET https://httpstat.us/404
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Sending HTTP request GET https://httpstat.us/404
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[101]
Received HTTP response headers after 319.9439ms - 404
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Received HTTP response headers after 319.9439ms - 404
info: System.Net.Http.HttpClient.ServiceA.LogicalHandler[101]
End processing HTTP request after 326.1409ms - 404
System.Net.Http.HttpClient.ServiceA.LogicalHandler: Information: End processing HTTP request after 326.1409ms - 404
info: System.Net.Http.HttpClient.ServiceB.LogicalHandler[100]
Start processing HTTP request GET https://httpstat.us/404
System.Net.Http.HttpClient.ServiceB.LogicalHandler: Information: Start processing HTTP request GET https://httpstat.us/404
info: System.Net.Http.HttpClient.ServiceB.ClientHandler[100]
Sending HTTP request GET https://httpstat.us/404
System.Net.Http.HttpClient.ServiceB.ClientHandler: Information: Sending HTTP request GET https://httpstat.us/404
info: System.Net.Http.HttpClient.ServiceB.ClientHandler[101]
Received HTTP response headers after 344.5937ms - 404
System.Net.Http.HttpClient.ServiceB.ClientHandler: Information: Received HTTP response headers after 344.5937ms - 404
info: System.Net.Http.HttpClient.ServiceB.LogicalHandler[101]
End processing HTTP request after 350.932ms - 404
System.Net.Http.HttpClient.ServiceB.LogicalHandler: Information: End processing HTTP request after 350.932ms - 404
ServiceA
发出请求,收到404Retry
未触发,因为仅处理 408
ServiceB
发出请求,收到404Retry
未触发,因为仅处理 408
/api/Home/408
调试日志:
info: System.Net.Http.HttpClient.ServiceA.LogicalHandler[100]
Start processing HTTP request GET https://httpstat.us/408
System.Net.Http.HttpClient.ServiceA.LogicalHandler: Information: Start processing HTTP request GET https://httpstat.us/408
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[100]
Sending HTTP request GET https://httpstat.us/408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Sending HTTP request GET https://httpstat.us/408
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[101]
Received HTTP response headers after 343.5167ms - 408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Received HTTP response headers after 343.5167ms - 408
Retry by ServiceA
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[100]
Sending HTTP request GET https://httpstat.us/408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Sending HTTP request GET https://httpstat.us/408
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[101]
Received HTTP response headers after 236.9796ms - 408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Received HTTP response headers after 236.9796ms - 408
Retry by ServiceA
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[100]
Sending HTTP request GET https://httpstat.us/408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Sending HTTP request GET https://httpstat.us/408
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[101]
Received HTTP response headers after 207.2602ms - 408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Received HTTP response headers after 207.2602ms - 408
Retry by ServiceA
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[100]
Sending HTTP request GET https://httpstat.us/408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Sending HTTP request GET https://httpstat.us/408
info: System.Net.Http.HttpClient.ServiceA.ClientHandler[101]
Received HTTP response headers after 203.3911ms - 408
System.Net.Http.HttpClient.ServiceA.ClientHandler: Information: Received HTTP response headers after 203.3911ms - 408
System.Net.Http.HttpClient.ServiceA.LogicalHandler: Information: End processing HTTP request after 1618.0826ms - 408
info: System.Net.Http.HttpClient.ServiceA.LogicalHandler[101]
End processing HTTP request after 1618.0826ms - 408
ServiceA
发出请求,收到408Retry
在 200 毫秒延迟后触发
ServiceA
发出请求,收到408Retry
在 200 毫秒延迟后触发
ServiceA
发出请求,收到408Retry
在 200 毫秒延迟后触发
ServiceA
发出请求,收到408Retry
未触发,因为超过了最大重试次数
ServiceB
未被调用,因为状态代码是 408 而不是 404
我最终没有使用 PollyHttpClientBuilderExtensions.AddPolicyHandler
但我用它作为灵感来编写我自己的:https://github.com/App-vNext/Polly-Samples/blob/master/PollyDemos/Async/AsyncDemo08_Wrap-Fallback-WaitAndRetry-CircuitBreaker.cs