【问题标题】:Resilience4J Circuit Breaker to kick-in on specific HTTP status codeResilience4J 断路器启动特定的 HTTP 状态代码
【发布时间】:2020-07-06 19:23:12
【问题描述】:

我知道我们可以在构建 CircuitBreakerConfig 时使用 recordExceptions() 来注册断路器应转换为 OPEN 状态的异常。

代码

我正在使用resilience4j-feign 来装饰我的CircuitBreaker。如果您能指出一个代码示例,那将非常有帮助。

问题

如果出现特定 HTTP 状态代码(例如 503 Service Unavailable),如何启动断路器?

【问题讨论】:

  • 是的,但是您需要在 Exception 类中表示这些 http 错误;您拥有或来自标准 http 库。你用的是什么http框架?

标签: java http-status-codes feign circuit-breaker resilience4j


【解决方案1】:

来自文档,Create and configure a CircuitBreaker

// Create a custom configuration for a CircuitBreaker
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
  .recordExceptions(IOException.class, TimeoutException.class) // add you exceptions here!!!
  .ignoreExceptions(BusinessException.class, OtherBusinessException.class)
  .build();

记录为失败并因此增加的异常列表 失败率。任何匹配或继承自其中之一的异常 列表算作失败,除非通过显式忽略 忽略异常。

【讨论】:

    【解决方案2】:

    您需要为客户端的外部调用编写异常/响应处理程序,并根据收到的 http 状态抛出自定义异常。然后将这些异常注册为断路器配置中的记录异常。下面是一个小例子。 CB 将仅在 AbcException 上打开。 CB 配置为resilience4j.circuitbreaker.instances.bookService.record-exceptions=com.sk.example.cb.circuitbreakerr4j.AbcException

    @Service
    @Slf4j
    public class BookApiService {
      RestTemplate restTemplate = new RestTemplate();
      @CircuitBreaker(name = "bookService", fallbackMethod = "getBookFallback")
      public String getBook(){
        try {
          ResponseEntity<String> stringResponseEntity = restTemplate.getForEntity(new URI("http://localhost:8080/book"), String.class);
          if(null != stringResponseEntity){
            if(stringResponseEntity.getStatusCode().is2xxSuccessful()){
              return stringResponseEntity.getBody();
            }
          }
        } catch (URISyntaxException e) {
          e.printStackTrace();
        }catch (HttpServerErrorException e){
          log.error("Service unavailable",e);
          if(e.getMessage().startsWith("503")) {
            throw new AbcException();
          }else{
            throw e;
          }
        }
        return "";
      }

    【讨论】:

      【解决方案3】:

      TL;DR:使用自定义异常将 HTTP 状态(例如 503)从 HTTP 客户端(例如 Feign)传送到 Resilience4J

      1. Feign:实现和配置ErrorDecoder 以在 HTTP 状态(如 503)上抛出 自定义异常
      2. Resilience4J:记录使用断路器配置自定义异常。

      假装

      如果出现错误的 HTTP 状态代码,Feign 默认会抛出 FeignException。可以通过int status()方法获取状态码号。

      要自定义您的 feign-clients 错误处理,请配置 ErrorDecoder 的(自定义)实现

      如果您需要对处理意外响应进行更多控制,Feign 实例可以通过构建器注册自定义ErrorDecoder。 [..] 所有导致 HTTP 状态不在 2xx 范围内的响应都将触发ErrorDecoder 的解码方法,允许您处理响应、将失败包装到自定义异常中或执行任何其他处理.如果您想再次重试请求,请抛出RetryableException。这将调用注册的Retryer

      自定义 Feign 错误处理

      实现并配置自定义 ErrorDecoder 以在 HTTP 状态 503 的情况下引发异常。

      @Component
      @Slf4j
      public class CustomErrorDecoder implements ErrorDecoder {
          
          @Override
          public Exception decode(String methodKey, Response response) {
              
              switch (response.status()) {
                  case 400:
                      log.error("Status code {} on methodKey '{}'", response.status(), methodKey);
                  case 503:
                      return new ServiceUnavailableException("HTTP status 503 when calling " methodKey);
                  default:
                      return new Exception(response.reason());
              } 
          }
          
      }
      

      这将抛出您的自定义异常ServiceUnavailableException

      Resilienc4J 的断路器

      默认情况下,断路器会对异常做出反应。它会记录它们,如果在太短的时间内太多,它会打开电路。

      您可以在业务级别按预期配置要记录哪些异常以及要忽略哪些异常。

      在特定异常情况下触发断路器

      您可以配置 CiruitBreaker 以记录该异常Joke's answer 解释了如何做到这一点。

      另见

      【讨论】:

        猜你喜欢
        • 2021-06-02
        • 2021-07-02
        • 2020-04-27
        • 2020-12-19
        • 2020-04-23
        • 2022-01-06
        • 2020-11-02
        • 2020-03-11
        • 1970-01-01
        相关资源
        最近更新 更多