spring-amqp icon indicating copy to clipboard operation
spring-amqp copied to clipboard

Feature: Option for @RabbitListener to Not Retry on Fatal Exception

Open ryandanielspmc opened this issue 5 years ago • 3 comments

Based on my understanding, and what I saw, the @RabbitListener will retry even if a thrown exception is fatal per ConditionalRejectingErrorHandler.DefaultExceptionStrategy. There are many cases where it does not make sense to retry, like when the JSON in the message is not valid. There is no reason to try again, in this case. Therefore, it would be great for there to be an option, or some other way, out-of-the-box, to not reprocess the incoming message if the @RabbitListener errored in a way that does not make sense to retry.

The current workaround I came up with was to implement a RabbitRetryTemplateCustomizer which has an injected FatalExceptionStrategy, and customize the retry policy to check if the exception is fatal.

ryandanielspmc avatar Feb 19 '20 19:02 ryandanielspmc

I would say we can't make such an unconditioanl decision in the framework and some customized RetryPolicy is the way to go. We definitely may provide some out-of-the-box RetryPolicy based on your condition, but it won't make it as a default one anyway.

Does it make sense?

Thank you!

artembilan avatar Feb 19 '20 19:02 artembilan

Does it make sense?

Yes, absolutely that makes sense. I am not suggesting that no-retry be the default.

ryandanielspmc avatar Feb 19 '20 19:02 ryandanielspmc

Good. So, feel free to contribute such a custom RetryPolicy!

artembilan avatar Feb 19 '20 19:02 artembilan

https://stackoverflow.com/a/75652127

marcusvoltolim avatar Jan 30 '24 03:01 marcusvoltolim

@marcusvoltolim ,

Do you suggest that SimpleRetryPolicy covers such a use-case?

artembilan avatar Jan 31 '24 17:01 artembilan

From what I understand, yes! Just add a Map with the exceptions and false so that they are not retried and defaultValue=true

See one more constructor for that 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 or the
 * root cause is found. The default value indicates whether to retry or not for
 * exceptions (or super classes thereof) that are not found in the map.
 * @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 true to traverse the exception cause chain until a classified
 * exception is found or the root cause is reached.
 * @param defaultValue the default action.
 */
public SimpleRetryPolicy(int maxAttempts, Map<Class<? extends Throwable>, Boolean> retryableExceptions,
        boolean traverseCauses, boolean defaultValue) {...}

marcusvoltolim avatar Jan 31 '24 17:01 marcusvoltolim

Good. Closing as Not Planned.

artembilan avatar Jan 31 '24 17:01 artembilan

Other option:

public class IgnoreFatalErrorSimpleRetryPolicy extends SimpleRetryPolicy {
  private static final FatalExceptionStrategy exceptionStrategy =
      new ConditionalRejectingErrorHandler.DefaultExceptionStrategy();

  public IgnoreFatalErrorSimpleRetryPolicy(int maxAttempts) {
    super(maxAttempts);
  }

  @Override
  public boolean canRetry(RetryContext context) {
    return !exceptionStrategy.isFatal(context.getLastThrowable()) && super.canRetry(context);
  }

}

marcusvoltolim avatar Jan 31 '24 22:01 marcusvoltolim