Поток Spring Cloud и обработка Spring RetryTemplate вложенного исключения

#spring-cloud-stream #spring-retry #spring-cloud-stream-binder-kafka

#поток spring-cloud-stream #spring-повторная попытка #spring-cloud-stream-binder-kafka

Вопрос:

У меня есть проект Spring Cloud Stream, использующий Kafka binder, и я хочу добавить функциональность повтора, я пытаюсь использовать RetryTemplate и указать определенные исключения, которые я хочу обработать, но из-за того, что любое исключение обернуто MessageTransformationException, я не могу настроить его так, как я хочу. Есть ли способ обработать вложенное исключение?

Шаблон повторной попытки

 @StreamRetryTemplate
public RetryTemplate myRetryTemplate() {
  RetryTemplate retryTemplate = new RetryTemplate();
 
  ExceptionClassifierRetryPolicy exceptionClassifierRetryPolicy =
      new ExceptionClassifierRetryPolicy();
  Map<Class<? extends Throwable>, RetryPolicy> policyMap = new HashMap<>();
  policyMap.put(MyException.class, new SimpleRetryPolicy(4));
  exceptionClassifierRetryPolicy.setPolicyMap(policyMap);
  retryTemplate.setRetryPolicy(exceptionClassifierRetryPolicy);
  return retryTemplate;
}
  

Отслеживание стека

 org.springframework.integration.transformer.MessageTransformationException: Failed to transform Message in bean '...' for component ‘...'; nested exception is org.springframework.messaging.MessageHandlingException: error occurred during processing message in 'MethodInvokingMessageProcessor' [org.springframework.integration.handler.MethodInvokingMessageProcessor@4dba2d07]; nested exception is MyException
  

Таким образом, он игнорирует конфигурацию, которую я настроил для MyException

Ответ №1:

Вам нужно установить traverseCauses значение true в SimpleRetryPolicy .

 /**
 * Create a {@link SimpleRetryPolicy} with the specified number of retry attempts. If
 * traverseCauses is true, the exception causes will be traversed until a match is
 * found.
 * @param maxAttempts the maximum number of attempts
 * @param retryableExceptions the map of exceptions that are retryable based on the
 * map value (true/false).
 * @param traverseCauses is this cause traversable
 */
public SimpleRetryPolicy(int maxAttempts, Map<Class<? extends Throwable>, Boolean> retryableExceptions,
        boolean traverseCauses) {
  

Итак:

 new SimpleRetryPolicy(4, Collections.singletonMap(Exception.class, true), true);
  

Комментарии:

1. Спасибо, Гэри, работает ли это таким образом с Policyap? Когда я пытаюсь использовать одну SimpleRetryPolicy, она работает нормально, но не с картой политик, я изменил свой пример таким образом POLICYAP.put(MyException.class , новая SimpleRetryPolicy(4, Collections.singletonMap(MyException.class , верно), верно));

2. Я не заметил, что вы использовали ExceptionClassifierRetryPolicy — почему? Когда у вас все равно есть только одна политика? Он классифицирует исключение, чтобы найти правильную политику, и его классификатор не пересекает цепочку причин. Похоже, вам понадобится пользовательский классификатор исключений вместо карты политики, см. setExceptionClassifier() .

3. В реальном случае мне нужно обрабатывать несколько исключений с разным поведением, что, похоже, довольно часто бывает. Моя единственная проблема с пользовательским классификатором заключается в том, что если api / архитектура spring-retry изменится после обновления до новой версии, у меня возникнет проблема с моей пользовательской логикой. Как вы думаете, является ли это достаточно ценной функцией, чтобы включить ее в саму spring-retry?

4. Да; это относится к spring-retry — я добавил эту возможность в SimpleRetryPolicy несколько лет назад. Это также следует добавить в эту политику. Если вы внедряете новый классификатор, который extends SubclassClassifier<Throwable, RetryPolicy> не стесняйтесь отправлять запрос на извлечение. Или я могу взглянуть (после SpringOne), если вы предпочитаете.

5. На самом деле, новый классификатор может просто делегировать a BinaryExceptionClassifier , поэтому ему не потребуется много логики.