我知道我们可以recordExceptions()
在构建时使用CircuitBreakerConfig
它来注册断路器应转换为OPEN
状态的异常。
代码
我resilience4j-feign
用来装饰我的CircuitBreaker
. 如果您能指出我的代码示例,那将非常有帮助。
问题
如果出现特定的 HTTP 状态代码(例如,在503 Service Unavailable上) ,如何使断路器启动?
我知道我们可以recordExceptions()
在构建时使用CircuitBreakerConfig
它来注册断路器应转换为OPEN
状态的异常。
我resilience4j-feign
用来装饰我的CircuitBreaker
. 如果您能指出我的代码示例,那将非常有帮助。
如果出现特定的 HTTP 状态代码(例如,在503 Service Unavailable上) ,如何使断路器启动?
从文档中,创建和配置 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();
记录为失败并因此增加失败率的异常列表。任何匹配或从列表之一继承的异常都算作失败,除非通过 ignoreExceptions 明确忽略。
您需要为客户端的外部调用编写异常/响应处理程序,并根据收到的 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 "";
}
TL;DR:使用自定义异常将 HTTP 状态(例如 503)从 HTTP 客户端(例如 Feign)传送到 Resilience4J
ErrorDecoder
抛出自定义异常,如 503Feign 默认抛出一个FeignException
错误的 HTTP 状态码。您可以通过方法int status()获取状态代码编号。
要自定义您的 feign-clients 错误处理,请配置(自定义)实现ErrorDecoder
如果您需要对处理意外响应进行更多控制,Feign 实例可以
ErrorDecoder
通过构建器注册自定义。[..] 导致 HTTP 状态不在 2xx 范围内的所有响应都将触发ErrorDecoder
's decode 方法,允许您处理响应、将失败包装到自定义异常或执行任何其他处理。如果您想再次重试请求,请抛出RetryableException
. 这将调用注册的Retryer
.
实现并配置自定义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
。
默认情况下,断路器对异常做出反应。它会记录它们,如果在太短的时间内太多,它会打开电路。
您可以在业务级别上按预期配置要记录哪些异常以及忽略哪些异常。
您可以配置 CiruitBreaker 来记录该异常。笑话的答案解释了如何做到这一点。