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<String> 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 一起使用