Spring-Retry с автоматическим выключателем

Я пытаюсь использовать как механизм повторной попытки, так и механизм автоматического выключателя повторной попытки. Я попытался использовать обе аннотации (@Retryable и @CircuitBreaker) в конкретной функции (как показано ниже), но Circuit Breaker не работал.

@Service
public class CommandAndRetry {

    private static final Logger LOGGER = LoggerFactory.getLogger(SampleRetryService.class);

    @CircuitBreaker(maxAttempts = 1, openTimeout = 10000)
    @Retryable(
            value = {TypeOneException.class},
            maxAttempts = 3, backoff = @Backoff(2000))
    public void retryWhenException() throws TypeOneException {
        LOGGER.info("Retrying");
        throw new TypeOneException();
    }

    @Recover
    public void recover(Throwable t) throws Throwable {
        LOGGER.info("SampleRetryService.recover");
        throw t;
    }
}

Затем я попытался разделить функциональность на две разные функции, каждая из которых имеет @Retryable и @CircuitBreaker соответственно. В этом случае механизм повтора не работал. Пожалуйста, найдите ниже фрагмент кода.

PS: метод exec (метод прерывателя цепи) вызывается из контроллера.

@Service
public class CommandAndRetry {

    private static final Logger LOGGER = LoggerFactory.getLogger(SampleRetryService.class);


    @CircuitBreaker(maxAttempts = 1, openTimeout = 10000)
    public void exec() throws TypeOneException {
        retryWhenException();
    }

    @Retryable(
            value = {TypeOneException.class},
            maxAttempts = 3, backoff = @Backoff(2000))
    public void retryWhenException() throws TypeOneException {
        LOGGER.info("Retrying");
        throw new TypeOneException();
    }

    @Recover
    public void recover(Throwable t) throws Throwable {
        LOGGER.info("SampleRetryService.recover");
        throw t;
    }
}

Кто-нибудь может сказать, почему он так себя ведет.

Также сообщите, существует ли лучший способ реализовать как повторную попытку, так и автоматический выключатель. PS: я не хочу использовать resilience4j или retryTemplate.


person Tanay Mathur    schedule 05.09.2018    source источник
comment
Я думаю, это потому, что CircuitBreaker сам по себе Retryable.   -  person yegodm    schedule 06.09.2018
comment
Да, но есть ли возможность его настроить? как установка отсрочки   -  person Tanay Mathur    schedule 08.09.2018
comment
Первый не будет работать, потому что, как говорит @yegodm, он сам @Retryable - см. Мой ответ о том, как это сделать.   -  person Gary Russell    schedule 11.09.2018


Ответы (1)


Если вы хотите повторить попытку в автоматическом выключателе, они должны быть в разных bean-компонентах. Если вы вызываете один @Retryable непосредственно из другого в том же компоненте, вы обойдете перехватчик.

У меня это отлично работает ...

@SpringBootApplication
@EnableRetry
public class So52193237Application {

    public static void main(String[] args) {
        SpringApplication.run(So52193237Application.class, args);
    }

    @Bean
    public ApplicationRunner runner(Foo foo) {
        return args -> {
            try {
                foo.exec();
            }
            catch (Exception e) {
                try {
                    foo.exec();
                }
                catch (Exception ee) {
                    Thread.sleep(11000);
                    try {
                        foo.exec();
                    }
                    catch (Exception eee) {

                    }
                }
            }
        };
    }

    @Component
    public static class Foo {

        private static final Logger LOGGER = LoggerFactory.getLogger(Foo.class);

        private final Bar bar;

        public Foo(Bar bar) {
            this.bar = bar;
        }

        @CircuitBreaker(maxAttempts = 1, openTimeout = 10000, resetTimeout=10000)
        public void exec() throws TypeOneException {
            LOGGER.info("Foo.circuit");
            this.bar.retryWhenException();
        }

        @Recover
        public void recover(Throwable t) throws Throwable {
            LOGGER.info("Foo.recover");
            throw t;
        }

    }

    @Component
    public static class Bar {

        private static final Logger LOGGER = LoggerFactory.getLogger(Bar.class);

        @Retryable(value = { TypeOneException.class }, maxAttempts = 3, backoff = @Backoff(2000))
        public void retryWhenException() throws TypeOneException {
            LOGGER.info("Retrying");
            throw new TypeOneException();
        }

        @Recover
        public void recover(Throwable t) throws Throwable {
            LOGGER.info("Bar.recover");
            throw t;
        }

    }

}
person Gary Russell    schedule 11.09.2018
comment
Спасибо за ответ. Также я пытался настроить maxAttempts автоматического выключателя. Похоже, что maxAttempts автоматического выключателя постоянно, и мы не можем настроить его из файла свойств. Есть ли обходной путь для этого? - person Tanay Mathur; 12.09.2018
comment
Нет; это не; в отличие от @Retryable, у него нет атрибутов со вкусом ...Expression. Возможно, откройте новую проблему запроса функции для проекта. Я полагаю, вы можете дважды обернуть его в качестве обходного пути - повторная попытка вызывает автоматический выключатель (с = 1), который вызывает повторную попытку. - person Gary Russell; 12.09.2018
comment
Спасибо за быстрый ответ. Но это не дает мне конфигурации opentimeout и resetTimeouta - person Tanay Mathur; 12.09.2018
comment
Верно; им потребуются изменения кода в фреймворке, чтобы их можно было настраивать. - person Gary Russell; 12.09.2018
comment
Здесь уже есть открытая проблема. Я посмотрю на это. - person Gary Russell; 12.09.2018
comment
Кроме того, можем ли мы использовать автоматический выключатель Hystrix вместо пружинного выключателя? Требуются конфигурируемые настройки автоматического выключателя - person Tanay Mathur; 18.09.2018