Resilience4j 断路器不工作

Posted

技术标签:

【中文标题】Resilience4j 断路器不工作【英文标题】:Resilience4j Circuit Breaker is not working 【发布时间】:2022-01-06 00:24:23 【问题描述】:

我遇到了使用 Spring Cloud Resilience4j 实现断路器的问题。

按照一些教程,我尝试在项目中添加必要的依赖项。 另外,尝试添加配置,但仍然没有打开电路,也没有调用回退方法。

对于用例,我正在从我的服务调用一个外部 API,如果该外部 API 关闭,那么在几次调用之后,我需要启用断路器。

请从不同的文件中找到代码片段。

我是断路器模式的新手。任何帮助将不胜感激。

pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.5.5</version>
   <relativePath/> <!-- lookup parent from repository -->
</parent>
    <properties>
    <java.version>11</java.version>
    <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
<dependencies>
</project>

应用程序属性

resilience4j.circuitbreaker.instances.test-api.register-health-indicator=true
resilience4j.circuitbreaker.instances.test-api.minimum-number-of-calls=4
resilience4j.circuitbreaker.instances.test-api.failure-rate-threshold=50
resilience4j.circuitbreaker.instances.test-api.permitted-number-of-calls-in-half-open-state=3
resilience4j.circuitbreaker.instances.test-api.wait-duration-in-open-state=30s
resilience4j.circuitbreaker.instances.test-api.automatic-transition-from-open-to-half-open-enabled=true
resilience4j.circuitbreaker.instances.test-api.record-exceptions=com.testapi.exception.ServiceUnavailableError

服务类代码片段

@CircuitBreaker(name = "test-api", fallbackMethod = "storeResponseFallback")
    public TestResponse storeResponse(String apiURL, HttpEntity<String> entityrequest) 

        TestResponse testResponse = new TestResponse();
        Optional<ResponseEntity<TestResponse>> response = Optional.empty();
        Future<ResponseEntity<TestResponse>> responseFuture;

        ExecutorService executor = Executors.newFixedThreadPool(10);

        log.debug("Calling Extrenal API, Request Body: ", entityrequest.toString());

        try 
            //Service call returns a future
            responseFuture = executor.submit(() -> restTemplate.postForEntity(apiURL, entityrequest, TestResponse.class));
            response = Optional.ofNullable(responseFuture.get());
            log.info("Got response from external API");


            if ((response.isPresent()) && (response.get().hasBody())) 
                testResponse = response.get().getBody();
            

         catch (Exception exception) 
            log.error("External api call got failed with an error");
            Thread.currentThread().interrupt();            
            throw new ServiceUnavailableError();
        


        return testResponse;

    
    
    
    public TestResponse storeResponseFallback(ServiceUnavailableError ex) 
        log.error("Executing Fallback Method For General exceptions");
        throw new ServiceUnavailableError();
    

ServiceUnavailableError Java 文件

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ServiceUnavailableError extends RuntimeException
    private static final long serialVersionUID = 2382122402994502766L;

    private String message;


【问题讨论】:

【参考方案1】:

您的回退方法的签名是错误的。它应该包含实际方法的所有参数(在您的情况下,storeResponseFallback 是回退方法,storeResponse 是实际方法)以及异常。请确保删除 try catch 块。您不想自己处理异常,而是应该让断路器为您处理它。 请查看以下来自给定链接的代码 https://resilience4j.readme.io/docs/getting-started-3

@CircuitBreaker(name = BACKEND, fallbackMethod = "fallback")
public Mono<String> method(String param1) 
    return Mono.error(new NumberFormatException());


private Mono<String> fallback(String param1, IllegalArgumentException e) 
    return Mono.just("test");

尝试使用以下 yaml 文件 我将以下配置与您现有的代码一起使用,我使用 yaml 而不是属性文件。这似乎保持在打开状态并仅调用回退方法。

resilience4j.circuitbreaker:
  configs:
    default:
      slidingWindowSize: 4
      permittedNumberOfCallsInHalfOpenState: 10
      waitDurationInOpenState: 10000
      failureRateThreshold: 60
      eventConsumerBufferSize: 10
      registerHealthIndicator: true
    someShared:
      slidingWindowSize: 3
      permittedNumberOfCallsInHalfOpenState: 10
  instances:
    test-api:
      baseConfig: default
      waitDurationInOpenState: 500000
    backendB:
      baseConfig: someShared

这是更新后的回退方法

public TestResponse storeResponseFallback(String apiURL, String entityrequest, java.lang.Throwable t) 
        log.error("Executing Fallback Method For General exceptions "+t.getMessage());
        return new TestResponse("Frm Fallback");// Making sure to send a blank response
    

【讨论】:

我已经更新了回退方法的方法签名。但是,仍然面临同样的问题。 public TestResponse storeResponseFallback(String apiURL, HttpEntity&lt;String&gt; entityrequest, ServiceUnavailableError ex) log.error("Executing Fallback Method For General exceptions"); throw new ServiceUnavailableError(); 您到底遇到了什么问题?它会去catch块吗? 是的,它将进入 catch 块。在日志中,我可以看到它正在引发 ServiceUnavailableError 异常。在邮递员调用中,它也返回预期的错误消息。但是,在定义的调用次数之后,它也没有打开断路器。相反,它每次都调用主服务方法。 请去掉try catch块再执行 我试过了。但仍然面临同样的问题。

以上是关于Resilience4j 断路器不工作的主要内容,如果未能解决你的问题,请参考以下文章

Resilience4j + Grafana 仪表板,与 Spring Cloud 断路器一起使用?

如何在 Resilience4J 中实现多个具有相同配置的断路器

使用 Spring Boot 为 Resilience4J 的断路器配置 Bean

如何在 Spring Boot 中将 Resilience4j 断路器与 WebFlux 一起使用

SpringCloud升级之路2020.0.x版-39. 改造 resilience4j 粘合 WebClient

断路器立即回退