Spring-Retry с автоматическим выключателем
Я пытаюсь использовать как механизм повторных попыток, так и механизм прерывания пружинных повторов. Я пытался использовать обе аннотации (@Retryable и @CircuitBreaker) в определенной функции (как показано ниже), но автоматический выключатель не работал.
@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.
1 ответ
Если вы хотите повторить попытку в автоматическом выключателе, они должны быть в разных бинах. Если вы позвоните один @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;
}
}
}