I'm trying to use @Retryable
and @Recover
and there's clearly something I am missing.
The (very paraphrased, very simplified) code is essentially
// MyRetryableException is a RuntimeException
@Retryable(retryFor = MyRetryableException.class, maxAttempts = 3)
public void doSomething(String s) throws JustGiveUpException {
final var response = talkToSomething(s);
if (response.getStatus().equals("retryableProblem")) {
throw new MyRetryableException(s);
else if (response.getStatus().equals("someOtherProblem")) {
throw new JustGiveUpException(s);
}
}
// UnableToCommunicateException is a RuntimeException
@Recover
public void handleFailedRetries(MyRetryableException e, String s) {
throw new UnableToCommunicateException(s);
}
When the response status is retryableProblem
everything works as I'd expect. When I test the code using a mock that will always return a response with retryableProblem
I ultimately get back a UnableToCommunicateException
and can verify that talkToSomething
was indeed called three times.
But when the response status is someOtherProblem
I don't get what I'm expecting. I expected to get a JustGiveUpException
. But instead I get an ExhaustedRetryException
with a cause of JustGiveUpException
and a message of Cannot locate recovery method
. Though I do see that talkToSomething
is only called once.
Why is that happening? I'm telling the Retryable
annotation that it only should retry on MyRetryableException
. So why is it trying to retry/recover on another exception?
You can try below annotation on doSomething() method:
@Retryable(retryFor = MyRetryableException.class, notRecoverable=JustGiveUpException.class, maxAttempts = 3, backoff = @Backoff(delay = 2000))
Most probably, the spring-retry version that you are using, requires "notRecoverable" attribute to specify the Exception(s) which needs to be excluded from retry logic.
Hope it works.