Search code examples
spring-cloud-streamspring-retryspring-cloud-stream-binder-kafka

Spring Cloud Stream and Spring RetryTemplate handling of nested exception


I have a Spring Cloud Stream project using the Kafka binder and I want to add retry functionality, I am trying to use RetryTemplate and specify certain exceptions that I want to handle, but because of any exception is wrapped by MessageTransformationException I can't configure it in a way I want. Is there a way to handle a nested exception?

Retry template

@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;
}

Stacktrace

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

So it ignores config I set up for MyException


Solution

  • You need to set traverseCauses to true in the 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) {
    

    So:

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