[英]Spring Boot Resilience4J Annotation Not Opening Circuit
我已經檢查了網站上有關 Resilience4J 的問題,但他們的答案沒有任何運氣。 我正在嘗試在我的 Spring Boot 2.x 項目中實現來自 Resilience4J 的@CircuitBreaker
注釋。 斷路器是圍繞一個非常簡單的 function 實現的。 但是,當我提供一個壞的 URL 時,無論我發送多少次請求,電路都不會打開。 我什至將所有內容提取到一個獨立的應用程序中並運行 100 次,然后觀察它只是無休止地失敗。 知道我做錯了什么嗎?
@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;
}
}
配置文件直接取自 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
嘗試測試它的代碼
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();
}
}
}
}
}
我嘗試將 Circuitbreaker 注釋添加到方法本身。 我嘗試過創建供應商並對其進行裝飾。 我試過添加隔板,移除隔板。 我嘗試添加具有不同簽名的其他后備方法。 我嘗試過使用和不使用@Component
。
我最終在日志中得到的只有 100 次:
14:33:10.348 [main] INFO c.t.circuits.CircuitsApplication - Error caught in main loop
我不確定我錯過了什么。 任何幫助將不勝感激。
我認為這行不通。 首先,您將ResilientClient
實例化為new ResilientClient()
。 您必須使用創建的 Bean 而不是自己實例化它。 @CircuitBreaker
注釋使用 spring-aop。 因此,您必須將 class 作為 SpringBootApplicaiton 運行。
其次,您僅將HttpServerErrorException
和IOException
記錄為失敗。 因此斷路器將所有其他異常(除了上面提到的異常及其子異常)視為成功。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.