简体   繁体   English

Spring Boot Resilience4J 注解不开启电路

[英]Spring Boot Resilience4J Annotation Not Opening Circuit

I've checked the questions on the site about Resilience4J, but have not had any luck with their answers.我已经检查了网站上有关 Resilience4J 的问题,但他们的答案没有任何运气。 I'm trying to implement @CircuitBreaker annotation from Resilience4J in my Spring Boot 2.x project.我正在尝试在我的 Spring Boot 2.x 项目中实现来自 Resilience4J 的@CircuitBreaker注释。 The circuit breaker is implemented around a pretty straightforward function.断路器是围绕一个非常简单的 function 实现的。 However, when I supply a bad URL, the circuit is not opening, no matter how many times I send the request.但是,当我提供一个坏的 URL 时,无论我发送多少次请求,电路都不会打开。 I've gone so far as to extract everything into a standalone application and run it 100 times and observe it just endlessly failing.我什至将所有内容提取到一个独立的应用程序中并运行 100 次,然后观察它只是无休止地失败。 Any idea what I'm doing wrong?知道我做错了什么吗?

    @CircuitBreaker(name = "backendA")
    @Component
    public class ResilientClient {

        private HttpClient httpClient;

        private static final Logger log = LoggerFactory.getLogger(ResilientClient.class);

        public ResilientClient() {

            httpClient = HttpClient.newBuilder().build();
        }


        @Bulkhead(name = "backendA")
        public String processPostRequest(String body, String[] headers, String url) {

            HttpResponse<String> response = null;

            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .POST(HttpRequest.BodyPublishers.ofString(body))
                .headers(headers)
                .build();

            try {
                response =  httpClient.send(request, HttpResponse.BodyHandlers.ofString());
            } catch (IOException e) {
                throw new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR, "This is a remote exception");
            } catch (InterruptedException e) {
                e.printStackTrace();
                log.error("Interrupted Exception: " + e.getLocalizedMessage(), e);

            }
            return response != null ? response.body() : null;
    };

// None of these functions ever get invoked

    private String fallback(Throwable e){
        log.info("generic throwable caught");
        return "generic result";
    }

    private String fallback(String param1, String[] headers, String url, Throwable e) {
        log.info("Fallback method invoked for Throwable: " + param1);
        return null;
    }

    private String fallback(String param1, String[] headers, String url, ConnectException e) {
        log.info("Fallback method invoked for ConnectException: " + param1);
        return null;
    }

}


The config file is taken directly from the Github example配置文件直接取自 Github 示例

resilience4j.circuitbreaker:
  configs:
    default:
      registerHealthIndicator: false
      slidingWindowSize: 10
      minimumNumberOfCalls: 5
      permittedNumberOfCallsInHalfOpenState: 3
      automaticTransitionFromOpenToHalfOpenEnabled: true
      waitDurationInOpenState: 2s
      failureRateThreshold: 50
      eventConsumerBufferSize: 10
      recordExceptions:
        - org.springframework.web.client.HttpServerErrorException
        - java.io.IOException
      ignoreExceptions:
        - io.github.robwin.exception.BusinessException
    shared:
      registerHealthIndicator: true
      slidingWindowSize: 100
      permittedNumberOfCallsInHalfOpenState: 30
      waitDurationInOpenState: 1s
      failureRateThreshold: 50
      eventConsumerBufferSize: 10
      ignoreExceptions:
        - io.github.robwin.exception.BusinessException
  instances:
    backendA:
      baseConfig: default
    backendB:
      registerHealthIndicator: true
      slidingWindowSize: 10
      minimumNumberOfCalls: 10
      permittedNumberOfCallsInHalfOpenState: 3
      waitDurationInOpenState: 1s
      failureRateThreshold: 50
      eventConsumerBufferSize: 10
      recordFailurePredicate: io.github.robwin.exception.RecordFailurePredicate
resilience4j.retry:
  configs:
    default:
      maxRetryAttempts: 2
      waitDuration: 100
      retryExceptions:
        - org.springframework.web.client.HttpServerErrorException
        - java.io.IOException
      ignoreExceptions:
        - io.github.robwin.exception.BusinessException
  instances:
    backendA:
      maxRetryAttempts: 3
    backendB:
      maxRetryAttempts: 3
resilience4j.bulkhead:
  configs:
    default:
      maxConcurrentCalls: 100
  instances:
    backendA:
      maxConcurrentCalls: 10
    backendB:
      maxWaitDuration: 10ms
      maxConcurrentCalls: 20

resilience4j.thread-pool-bulkhead:
  configs:
    default:
      maxThreadPoolSize: 4
      coreThreadPoolSize: 2
      queueCapacity: 2
  instances:
    backendA:
      baseConfig: default
    backendB:
      maxThreadPoolSize: 1
      coreThreadPoolSize: 1
      queueCapacity: 1

resilience4j.ratelimiter:
  configs:
    default:
      registerHealthIndicator: false
      limitForPeriod: 10
      limitRefreshPeriod: 1s
      timeoutDuration: 0
      eventConsumerBufferSize: 100
  instances:
    backendA:
      baseConfig: default
    backendB:
      limitForPeriod: 6
      limitRefreshPeriod: 500ms
      timeoutDuration: 3s

Code to try testing it尝试测试它的代码

SpringBootApplication
public class CircuitsApplication {

    private static final Logger logger = LoggerFactory.getLogger(CircuitsApplication.class);

    static ResilientClient resilientClient = new ResilientClient();

    public static void main(String[] args) {
        //SpringApplication.run(CircuitsApplication.class, args);
        for (int i = 0; i < 100; i++){
            try {
                String body = "body content";
                String[] headers = new String[]{"header", "value"};
                String url = "http://a.bad.url";
                String result = resilientClient.processPostRequest(body, headers, url);
                logger.info(result);
            } catch (Exception ex){
                logger.info("Error caught in main loop");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

I've tried adding the Circuitbreaker annotation to the method itself.我尝试将 Circuitbreaker 注释添加到方法本身。 I've tried creating a supplier and decorating it.我尝试过创建供应商并对其进行装饰。 I've tried adding the Bulkhead, removing the Bulkhead.我试过添加隔板,移除隔板。 I've tried adding additional fallback methods with different signatures.我尝试添加具有不同签名的其他后备方法。 I've tried with and without @Component .我尝试过使用和不使用@Component

All I end up getting in my logs is this 100 times:我最终在日志中得到的只有 100 次:

14:33:10.348 [main] INFO c.t.circuits.CircuitsApplication - Error caught in main loop

I'm not sure what I'm missing.我不确定我错过了什么。 Any help would be greatly appreciated.任何帮助将不胜感激。

I don't think this will work.我认为这行不通。 Firstly, you are instantiating your ResilientClient as new ResilientClient() .首先,您将ResilientClient实例化为new ResilientClient() You have to use the created Bean not instantiate it yourselves.您必须使用创建的 Bean 而不是自己实例化它。 The @CircuitBreaker annotation uses spring-aop. @CircuitBreaker注释使用 spring-aop。 So you will have to run you class as SpringBootApplicaiton.因此,您必须将 class 作为 SpringBootApplicaiton 运行。

Secondly, you are only recording HttpServerErrorException and IOException as failures.其次,您仅将HttpServerErrorExceptionIOException记录为失败。 So circuit breaker treats all other exceptions (except the ones mentioned above and their children) as success.因此断路器将所有其他异常(除了上面提到的异常及其子异常)视为成功。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM