[英]error handling with reactiveFeignClient and CircuitBreaker
我們正在使用反應式偽裝客戶端(com.playtika.reactivefeign:feign-reactor-spring-cloud-starter:3.2.0)
斷路器版本:org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j:2.1.0
和 spring boot 應用程序版本 org.springframework.boot' version '2.6.6
當我們從反應式偽裝客戶端收到錯誤(例如 404 錯誤)時
@ReactiveFeignClient(name = "someRestClient", url = "${react-gpi-service.url}",configuration = AuthConfigurationsomeRestClient.class, fallbackFactory = someRestClienttFallbackFactory.class)
@Profile("!test")
public interface someRestClient {
@PostMapping(value = "/v2/{entity}/any", produces = MediaType.ALL_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
Mono<String> any(@PathVariable(value = "entity")
它遍歷錯誤解碼器以檢查是否應該重試
@Slf4j
@RequiredArgsConstructor
public class RetryableErrorDecoder implements ErrorDecoder {
private static ErrorDecoder defaultErrorDecoder = new Default();
private final String clientName;
public Exception decode(String methodKey, Response response) {
String body = "";
try {
body = IOUtils.toString(response.body().asInputStream(), StandardCharsets.UTF_8);
} catch (Exception e) {
log.error("failed to parse error response body", e);
}
log.error("In RetryableErrorDecoder, got an error from {}. status: {}, body: {}, reason: {}, request: {}",
clientName, response.status(), body, response.reason(), response.request());
if (response.status() == HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE ||
response.status() == HttpStatusCodes.STATUS_CODE_BAD_GATEWAY) {
log.warn("Retry on error 503 or 502");
return createRetryableException(response, "Service Unavailable 503, 502");
} else {
Exception decode = defaultErrorDecoder.decode(methodKey, response);
if (decode instanceof FeignException &&
decode.getMessage().contains("authorizing")) {
log.warn("Retry on {}", decode.getMessage());
return createRetryableException(response, "Service authorizing problem");
}
return decode;
}
}
private Exception createRetryableException(Response response, String message) {
return new RetryableException(
response.status(),
message,
response.request().httpMethod(),
null,
null,
response.request());
}
}
之后它轉到 Circuit beaker predicate
public class someFailurePredicate implements Predicate<Throwable> {
@Override
public boolean test(Throwable throwable) {
return throwable instanceof ThirdPartyException
|| throwable instanceof ReadTimeoutException
|| throwable instanceof OutOfRetriesException;
}
}
然后進入 fallBackFactory 機制,因為斷路器需要 fallback 方法,所以斷路器謂詞再次被激活。
@Component
public class someRestClientFallbackFactory implements FallbackFactory<someRestClient> {
@Override
public someRestClient apply(Throwable throwable) {
return new someRestClientFallback(throwable);
}
}
public class someRestClientFallback implements someRestClient {
private final Throwable cause;
public someClientFallback(Throwable cause) {
this.cause = cause;
}
public Mono<String> performSearchRequest(String entity,
) {
return Mono.error(cause);
}
}
因為我們有兩種錯誤處理機制,電路謂詞調用兩次並復制錯誤。
我試圖將重試機制(錯誤解碼器)移至回退方法,但回退工廠方法接受可拋出的並且 reactiveFeignClientException 沒有狀態代碼,因此很難確定我們是否應該進行重試。
如果我刪除后備方法,我會收到此錯誤消息:
org.springframework.cloud.client.circuitbreaker.NoFallbackAvailableException: No fallback available.
我們需要添加它,但是我們有兩個機制和一個重復的斷路器謂詞計數
Reactive Feign Client 默認啟用自己的 CB,可以通過將 reactive.feign.circuit.breaker.enabled 設置為 false 來禁用它 - https://github.com/PlaytikaOSS/feign-reactive/blob/develop/feign-反應堆彈簧配置/README.md
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.