基于请求条件的断路器
Circuit breaker based on the condition in request
我需要设置断路策略,以便它只针对某些特定请求断路。
我有一种网关 A 调用 API B 进而调用 C 或 D。我正在 A 中设置断路器策略。到达 A 的初始请求有一个参数,稍后用于决定是调用 C 还是 D,比方说 http://gateway.A.com?usageParam=C
。我想以这种方式配置断路器,该电路可以分别为 C 和 D 打开。我的意思是,如果 D 失败,使用 usageParam=D
的调用应该立即失败,但 usageParam=C
应该仍然正常,反之亦然。
简单来说,Circuit Breaker 只能有一个状态。其中之一:Closed
、Open
、Half-Open
.
您应该将 CB 视为代理。如果下游系统被认为是健康的,它允许每个请求通过它。如果 CB 检测到瞬时故障(通过检查响应(如果有)),那么它将通过拒绝所有请求来缩短执行速度。
因此,如果您想区分 C
和 D
下游系统的健康状况,那么您需要两个 CB(每个一个)。这允许您分别允许或拒绝针对不同子系统的传出请求。
选项 A
您可以将两个 CB 放在服务中 A
。在这里你可以注册两个命名为 HttpClients 的装饰有不同的断路器:
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());
但是你必须手动进行路由,像这样:
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("..."),
};
选项 B
您可以将两个 CB 放在服务中 B
。在这里您可以注册两个类型化的 HttpClients,它们装饰有不同的 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());
我需要设置断路策略,以便它只针对某些特定请求断路。
我有一种网关 A 调用 API B 进而调用 C 或 D。我正在 A 中设置断路器策略。到达 A 的初始请求有一个参数,稍后用于决定是调用 C 还是 D,比方说 http://gateway.A.com?usageParam=C
。我想以这种方式配置断路器,该电路可以分别为 C 和 D 打开。我的意思是,如果 D 失败,使用 usageParam=D
的调用应该立即失败,但 usageParam=C
应该仍然正常,反之亦然。
简单来说,Circuit Breaker 只能有一个状态。其中之一:Closed
、Open
、Half-Open
.
您应该将 CB 视为代理。如果下游系统被认为是健康的,它允许每个请求通过它。如果 CB 检测到瞬时故障(通过检查响应(如果有)),那么它将通过拒绝所有请求来缩短执行速度。
因此,如果您想区分 C
和 D
下游系统的健康状况,那么您需要两个 CB(每个一个)。这允许您分别允许或拒绝针对不同子系统的传出请求。
选项 A
您可以将两个 CB 放在服务中 A
。在这里你可以注册两个命名为 HttpClients 的装饰有不同的断路器:
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());
但是你必须手动进行路由,像这样:
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("..."),
};
选项 B
您可以将两个 CB 放在服务中 B
。在这里您可以注册两个类型化的 HttpClients,它们装饰有不同的 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());