#spring #spring-cloud #asynchttpclient #circuit-breaker #resilience4j
#весна #spring-cloud #asynchttpclient #автоматический выключатель #отказоустойчивость 4j
Вопрос:
Я пытаюсь использовать библиотеку spring cloud resilience4j для реализации автоматического отключения, когда API поставщика возвращает 500 ошибок или когда истекает время ожидания, API вызывается с использованием AsyncHttpClient. Проблема, по-видимому, заключается в том, что автоматический выключатель никогда не открывается, а метод резервного копирования никогда не выполняется, когда API возвращает 500 ошибок.
Может ли это быть связано с тем, что я переопределяю OnFailure (сделайте это для захвата показателей)
Завод объявляется следующим образом:
@Autowired
private CircuitBreakerFactory circuitBreakerFactory;
Заводская конфигурация определяется следующим образом:
@Bean
public Customizer<Resilience4JCircuitBreakerFactory> specificCustomConfiguration1() {
TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(2))
.build();
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofMillis(1000))
.slidingWindowSize(2)
.build();
return factory -> factory.configure(builder -> builder.circuitBreakerConfig(circuitBreakerConfig)
.timeLimiterConfig(timeLimiterConfig).build(), "circuitBreaker");
}
API вызывается с помощью следующего метода, который также имеет автоматический выключатель и метод .run:
private void getRecommendationsAsync(final GatewayRecommendationsRequest request,
final String variantName,
final ThinkCallbackHandler callbackHandler)
throws URISyntaxException, JsonProcessingException {
CircuitBreaker circuitBreaker = circuitBreakerFactory.create("circuitBreaker");
final AsyncHttpClient.BoundRequestBuilder builder = requestBuilder
.prepareRequest(asyncHttpClient, request, variantName);
circuitBreaker.run(() -> builder.execute(new AsyncCompletionHandler<Response>() {
@Override
public Response onCompleted(final Response response)
throws Exception {
processResponseStatus(response, variantName);
GatewayRecommendations gatewayRecommendations = ((ThinkResponseMapper) responseMapper).map(request,
response,
useCaseId,
variantName);
validator.validateResponse("/v1/recommendations", Request.Method.GET, response, gatewayRecommendations);
callbackHandler.onSuccess(gatewayRecommendations);
return response;
}
@Override
public void onThrowable(final Throwable t) {
callbackHandler.onFailure(t, recommendationsUri " " parameters.toString(), variantName);
}
}), throwable -> fallback());
}
и, наконец, вот резервный метод, который я хотел бы вызвать:
public String fallback() {
LOGGER.warn("The fallback method is being used");
System.out.println("Fallback Method is being executed");
return "The circuit breaker is open";
}
Ответ №1:
Используете ли вы AsyncHttpClient?
Вы могли бы попробовать наш стартер Resilience4j Spring Boot 2. Он обеспечивает поддержку аннотаций, внешнюю конфигурацию, метрики, повторные попытки и многие другие функции.
Если бы вы могли вернуть a CompletableFuture
, это могло бы выглядеть следующим образом:
@CircuitBreaker(name = "circuitBreaker", fallbackMethod="fallback")
public CompletableFuture<GatewayRecommendations> getRecommendationsAsync(final GatewayRecommendationsRequest request,
final String variantName,
final ThinkCallbackHandler callbackHandler)
throws URISyntaxException, JsonProcessingException {
final AsyncHttpClient.BoundRequestBuilder builder = requestBuilder
.prepareRequest(asyncHttpClient, request, variantName);
return builder.execute().toCompletableFuture()
.exceptionally(t -> { /* Something wrong happened... */ } )
.thenApply(response -> { /* Validate response and extract GatewayRecommendations */
});
}
public CompletableFuture<GatewayRecommendations> fallback(RequestNotPermitted ex) {
// The circuit breaker is open
// Return a static list of recommendations
return CompletableFuture.completedFuture(..)
}
Комментарии:
1. Привет, Роберт, спасибо, что перезвонил. Да, я понял, что проблема заключалась в типе возвращаемого значения и выполнении methid. Нет его com.ning.http.client. Версия AsyncHttpClient, которая, к сожалению, не имеет завершающего метода future. Посмотрим на это и, возможно, перепишем службу на реактивную модель. Спасибо, Зейн
2. Если ответ все еще был полезен, пожалуйста, примите его 😉
3. Конечно. Переход на реактивный будет использовать реактивный CB, спасибо, Роберт 🙂