Попытка исключить исключение с помощью @Retryable - вызывает исключение ExhaustedRetryException
Я пытаюсь использовать @Retryable
на метод, который вызывает шаблон REST. Если ошибка возвращается из-за ошибки связи, я хочу повторить попытку, в противном случае я хочу просто вызвать исключение при вызове.
Когда возникает исключение ApiException, вместо @Retryable оно выбрасывается и игнорируется, я получаю ExhaustedRetryException
и жалоба на нехватку достаточного количества "восстанавливаемых" средств, @Recover
методы.
Я думал, что увижу, может ли просто наличие восстанавливаемого метода сделать его счастливым и по-прежнему работать так, как надеялись. Не так много. Вместо того чтобы генерировать исключение, он вызывал восстанавливаемый метод.
@Retryable(exclude = ApiException include = ConnectionException, maxAttempts = 5, backoff = @Backoff(multiplier = 2.5d, maxDelay = 1000000L, delay = 150000L))
Object call(String domainUri, ParameterizedTypeReference type, Optional<?> domain = Optional.empty(), HttpMethod httpMethod = HttpMethod.POST) throws RestClientException {
RequestEntity request = apiRequestFactory.createRequest(domainUri, domain, httpMethod)
log.info "************************** Request Entity **************************"
log.info "${request.toString()}"
ResponseEntity response
try {
response = restTemplate.exchange(request, type)
log.info "************************** Response Entity **************************"
log.info "${response.toString()}"
} catch (HttpStatusCodeException | HttpMessageNotWritableException httpException) {
String errorMessage
String exceptionClass = httpException.class.name.concat("-")
if(httpException instanceof HttpStatusCodeException) {
log.info "************************** API Error **************************"
log.error("API responded with errors: ${httpException.responseBodyAsString}")
ApiError apiError = buildErrorResponse(httpException.responseBodyAsString)
errorMessage = extractErrorMessage(apiError)
if(isHttpCommunicationError(httpException.getStatusCode().value())) {
throw new ConnectionException(exceptionClass.concat(errorMessage))
}
}
errorMessage = StringUtils.isBlank(errorMessage) ? exceptionClass.concat(httpException.message) : exceptionClass.concat(errorMessage)
throw new ApiException(httpMethod, domainUri, errorMessage)
}
if (type.type == ResponseEntity) {
response
}
else response.body
}
@Recover
Object connectionException(ConnectionException connEx) {
log.error("Retry failure - communicaiton error")
throw new ConnectionException(connEx.class.name + " - " + connEx.message)
}
Любые идеи будут оценены. Это ошибка или ошибка оператора? Это использует Spring Boot 1.3.6 и Spring-Retry 1.1.3.
1 ответ
Ваш синтаксис include/exclude выглядит плохо - он даже не скомпилируется.
Я только что написал быстрый тест, и он работает точно так, как ожидалось, если у вас есть ноль @Recover
методы...
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.annotation.Retryable;
@SpringBootApplication
@EnableRetry
public class So38601998Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(So38601998Application.class, args);
Foo bean = context.getBean(Foo.class);
try {
bean.out("foo");
}
catch (Exception e) {
System.out.println(e);
}
try {
bean.out("bar");
}
catch (Exception e) {
System.out.println(e);
}
}
@Bean
public Foo foo() {
return new Foo();
}
public static class Foo {
@Retryable(include = IllegalArgumentException.class, exclude = IllegalStateException.class,
maxAttempts = 5)
public void out(String foo) {
System.out.println(foo);
if (foo.equals("foo")) {
throw new IllegalArgumentException();
}
else {
throw new IllegalStateException();
}
}
}
}
Результат:
foo
foo
foo
foo
foo
java.lang.IllegalArgumentException
bar
java.lang.IllegalStateException
Если вы просто добавите
@Recover
public void connectionException(IllegalArgumentException e) {
System.out.println("Retry failure");
}
Ты получаешь
foo
foo
foo
foo
foo
Retry failure
bar
org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method; nested exception is java.lang.IllegalStateException
Так что вам нужно поймать все @Recover
метод...
@Recover
public void connectionException(Exception e) throws Exception {
System.out.println("Retry failure");
throw e;
}
Результат:
foo
foo
foo
foo
foo
Retry failure
bar
Retry failure
java.lang.IllegalStateException