Отказоустойчивость Spring Cloud 4j прерыватель цепи, не вызывающий резервный вариант

#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, спасибо, Роберт 🙂