Do HTTP policies instances are shared when I create named HTTP client in each request using IHttpClientFactory
?
I am using the IHttpClientFactory
to create a named-http-client per request:
var workloadHttpClient = _httpClientFactory.CreateClient(product.ToString());
var response = await workloadHttpClient.SendAsync(message);
I am defining named-clients, and Polly's Circuit Breaker per such client:
services
.AddSingleton<IProductProvider, XProvider>()
.AddHttpClient(Products.X.ToString())
.AddPolicyHandler(BuildCircuitBreakerPolicy());
services
.AddSingleton<IProductProvider, YProvider>()
.AddHttpClient(Products.Y.ToString())
.AddPolicyHandler(BuildCircuitBreakerPolicy());
With this definition, will the circuit breaker work?
Will all the created clients named "X" use the same instance of the circuit breaker policy, thus really counting all the failures from all executions of XProvider?
The AddPolicyHandler
calls the AddHttpClientHandler
to register a PolicyHttpMessageHandler
under the hood. This handler is a DelegatingHandler
.
Whenever you use HttpClientFactory
then the underlying HttpClientHandler
s (and the associated DelegatingHandler
s) are cached for 2 minutes by default.
That means whenever you create a new HttpClient
with the same name then a cached HttpClientHandler
will be used. After 2 minutes elapses then the handler is marked as to-be-cleaned. Whenever a new HttpClient
with the same name is requested then a new HttpClientHandler
will be created.
Here you can find a simplified demo to show you that the CB indeed breaks on the second HttpClient
instance:
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Polly;
public class Program
{
public static async Task Main()
{
var collection = new ServiceCollection();
collection.AddHttpClient();
collection.AddHttpClient("A")
.AddPolicyHandler(GetCircuitBreakerPolicy());
var sp = collection.BuildServiceProvider();
var factory = sp.GetRequiredService<IHttpClientFactory>();
for(int i=0; i < 10; i++)
{
var client = factory.CreateClient("A");
var res = await client.GetAsync("http://httpstat.us/500");
Console.WriteLine(res.StatusCode);
}
}
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
=> Policy<HttpResponseMessage>
.HandleResult(res => res.StatusCode == HttpStatusCode.InternalServerError)
.CircuitBreakerAsync(1, TimeSpan.FromSeconds(2));
}
If you want to change this 2 minutes caching period then please check the HandlerLifetime
of the HttpClientFactoryOptions
.