2016-07-27 1 views
1

Я пытаюсь использовать @Retryable по методу, который вызывает шаблон REST. Если ошибка возникает из-за ошибки связи, я хочу повторить попытку, иначе я хочу просто вызвать исключение в вызове.Попытка исключить исключение с помощью @Retryable - вызывает выброс ExhaustedRetryException

Когда возникает 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.

ответ

0

Синтаксис 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 
+0

Можете ли вы уточнить, что это неправильно с синтаксисом? Я ничего не получаю при компиляции. Я попробую добавить пустой метод @Recover. – Les

+0

Итак, я включил метод @Recover для всех, и исключение, которое оно получает, - это тот, который я сказал, чтобы исключить. – Les

+0

Правильно. Если у вас есть хотя бы один метод '@ Recover', вам нужно всего лишь выделить исключения для исключенных (не повторенных) исключений; он может воссоздать, как у меня). Re синтаксис: сравните ваш: 'exclude = ApiException include = ConnectionException,' my mine: 'include = IllegalArgumentException.class, exclude = IllegalStateException.class,' - требуется запятая и '.class'. –

Смежные вопросы