0

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

MikeV
  • 3
  • 3

1 Answers1

0

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);
Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • Thanks, Gary does it work in this way with policyMap? When I trying with single SimpleRetryPolicy it works fine but not with a policy map, I have modified my example in this way policyMap.put(MyException.class, new SimpleRetryPolicy(4, Collections.singletonMap(MyException.class, true), true)); – MikeV Aug 28 '20 at 15:15
  • I didn't notice you were using an `ExceptionClassifierRetryPolicy` - why? When you only have one policy anyway? It classifies the exception to find the right policy and its classifier doesn't traverse the cause chain. It looks like you would need a custom exception classifier instead of the policy map see `setExceptionClassifier()`. – Gary Russell Aug 28 '20 at 15:34
  • In a real case, I need to handle multiple exceptions with different behavior, that seems like quite often case. My only concern with a custom classifier is that if spring-retry api/architecture will change after updating to a new version I will have an issue with my custom logic. Do you think is it a valuable enough feature to include it to the spring-retry itself? – MikeV Aug 28 '20 at 15:50
  • Yes; it belongs in spring-retry - I added the capability to `SimpleRetryPolicy` several years ago. It should be added to this policy too. If you implement a new classifier that `extends SubclassClassifier` feel free to issue a pull request. Or I can take a look (after SpringOne) if you prefer. – Gary Russell Aug 28 '20 at 15:58
  • Actually, the new classifier can simply delegate to a `BinaryExceptionClassifier` so it won't need much logic itself. – Gary Russell Aug 28 '20 at 16:22