I need to set up the circuit break policy so that it would break the circuit only for some specific requests.
I have a sort of a gateway A calling API B which in turn calls C or D. I'm setting up a circuit breaker policy in A. Initial request arriving on A has a parameter that is later used to decide whether to call C or D, lets say http://gateway.A.com?usageParam=C
. I'd like to have circuit breaker configured in such a way, that circuit could be open separately for C and D. I mean that if D is failing, calls with usageParam=D
should fail immediately but usageParam=C
should still go fine and vice versa.
To put it simple a Circuit Breaker can have only just a single state. One of these: Closed
, Open
, Half-Open
.
You should consider the CB as a proxy. It allows each request to go trough it if the downstream system is considered health. If CB detects transient failure (by examining the responses if any) then it will shortcut the execution by denying all requests.
So, if you want to differentiate the healthiness of C
and D
downstream systems then you would need two CBs (one for each). That allows you to separately allow or deny outgoing requests against different subsystems.
You can place the two CBs inside service A
. Here you can register two named HttpClients which are decorated with different Circuit Breakers:
private IAsyncPolicy<HttpResponseMessage> GetCBPolicy()
=> HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(2, TimeSpan.FromSeconds(1));
...
services.AddHttpClient("CService", c => {
c.BaseAddress = new Uri(BServiceBasePath);
...
})
.AddPolicyHandler(GetCBPolicy());
services.AddHttpClient("DService" c => {
c.BaseAddress = new Uri(BServiceBasePath);
...
})
.AddPolicyHandler(GetCBPolicy());
But you have to do the routing manually, something like this:
if(!Context.Request.Query.TryGetValue("usageParam", out var usage))
return;
HttpClient client = usage switch
{
"C" => _clientFactory.CreateClient("CService"),
"D" => _clientFactory.CreateClient("DService"),
_ => throw new NotSupportedException("..."),
};
You can place the two CBs inside service B
. Here you can register two typed HttpClients which are decorated with different Circuit Breakers:
private IAsyncPolicy<HttpResponseMessage> GetCBPolicy()
=> HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(2, TimeSpan.FromSeconds(1));
...
services.AddHttpClient<ICService, CService>()
.AddPolicyHandler(GetCBPolicy());
services.AddHttpClient<IDService, DService>()
.AddPolicyHandler(GetCBPolicy());