正如我们在上面日志的屏幕截图中看到的,当我们从订单服务调用客户服务并返回错误但订单服务仍然成功并且回退值用于响应。因此,通过在订单服务中使用回退策略,我们能够处理客户服务中的故障。
断路器策略此断路器策略建议您需要有某种机制或逻辑来不调用特定服务,以防该服务因前几个请求而永久失败。当服务请求失败计数超过某个预先配置的阈值时,此断路器策略允许您配置为在配置的时间段内阻止对特定失败服务的 HTTP 请求。
考虑从订单服务到客户服务的 HTTP 请求失败的场景。来自客户服务的这个错误可能是永久性的,也可能是暂时的。现在即使在重试期间请求也失败了,因此您使用回退策略为响应提供了一些替代值。但是现在由于很少有连续呼叫客户服务失败,所以一段时间(比如几分钟)你不想浪费时间打电话给客户服务而是假设它会返回一个错误并使用备用响应来处理请求订购服务。
此逻辑假设,如果服务连续失败几次,则该服务存在一些永久性问题,可能需要一些时间来纠正问题。因此,让我们不要浪费时间调用或重试失败的服务,而是采取备用回退路径为服务提供一些时间来恢复。
按照这个断路器逻辑,订单服务会向客服请求客户姓名,如果客服连续2次返回异常,则电路将断开(即电路将打开)1分钟,并持续1分钟订单服务不会打电话给客户服务,而是自己假设客户服务会返回错误。
为了模拟客户服务的永久性故障,我们将使用客户服务中的 GetCustomerNameWithPermFailure 操作,我们用于演示回退策略。
要在 ASP.NET Core 中使用 Polly 实现断路器逻辑,我们需要声明 CircuitBreakerPolicy 类型的对象并定义策略,如下面的代码所示
private static CircuitBreakerPolicy _circuitBreakerPolicy; public OrderController(ILogger<OrderController> logger, IHttpClientFactory httpClientFactory) { if (_circuitBreakerPolicy == null) { _circuitBreakerPolicy = Policy.Handle<Exception>() .CircuitBreaker(2, TimeSpan.FromMinutes(1)); } }上面的代码示例将创建一个断路器策略,该策略定义在调用服务时如果连续 2 次出现异常,则电路将中断(对服务的调用将被阻止)2 分钟的时间跨度。
同样在上面的代码中,我们已经指定断路器策略处理通用异常,因此它会因所有类型的异常而中断,但您甚至可以为更具体的异常(如 HttpRequestException)配置断路器策略,然后它只会因以下异常而中断类型 HttpRequestException。
接下来,我们将在订单服务中添加一个新的操作方法,它将利用断路器策略对象向客户服务的操作方法 (GetCustomerNameWithPermFailure) 发出 HTTP 请求,该方法返回错误。断路器策略用于处理客户服务的故障,在客户服务连续 2 次失败后 1 分钟内不拨打任何电话。
[HttpGet] [Route("GetOrderByCustomerWithCircuitBreaker/{customerCode}")] public OrderDetails GetOrderByCustomerWithCircuitBreaker(int customerCode) { try { _httpClient = _httpClientFactory.CreateClient(); _httpClient.BaseAddress = new Uri(apiurl); var uri = "/api/Customer/GetCustomerNameWithPermFailure/" + customerCode; var result = _circuitBreakerPolicy.Execute(() => _httpClient.GetStringAsync(uri).Result); _orderDetails.CustomerName = result; return _orderDetails; } catch (Exception ex) { _logger.LogError(ex, "Excpetion Occurred"); _orderDetails.CustomerName = "Customer Name Not Available as of Now"; return _orderDetails; } }断路器策略对象使用委托在 Execute() 委托中执行所需的对客户服务的 HTTP 调用。如果 HTTP 调用引发异常,该异常正在由 catch 块处理以提供客户名称的替代值。
让我们在 ASP.NET Core 中运行和测试 Polly 的断路器策略。在 Visual Studio 中运行解决方案后,两个项目(即客户和订单)都应该启动。两个服务都开始转到订购服务后,您应该会看到以下来自 swagger (OpenAPI) 的屏幕