OK, this is actually not about the winter, which as we all know has already come . It is about Spring Retry, a small Spring Framework library that allows us to add retry functionality to any task that should be retryable.

There’s a very good tutorial here , explaining how the simple retry and recovery is set up. It explains very well how to add a spring-retry dependency , use @Retryable and @Recover annotation and use RetryTemplate with simple policies. What I’d like to linger on is a slightly more complicated case when we actually want to apply different retry behavior based on the type of the exception. This makes sense because we might know that some exceptions are recoverable and some are not, and therefore it doesn’t make too much sense to try and recover from them. For that, there is a specific retry strategy implementation which is called ExceptionClassifierRetryPolicy , which is used with the Spring RetryTemplate .

Let’s suppose we can only recover from IO Exceptions and skip all others . We will create three classes to extend RetryCallback and one class to extend RecoveryCallback to better show what happens inside:

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters

The output for it is as follows:

*** Executing successfull callback...
Success callback: attempt 0

Then the Exception :

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
*** Executing Exception callback...
Exception callback: attempt 0
Attempts exhausted. Total: 1
Last exception: Test Exception

And at last our IOException :

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
*** Executing IO Exception callback...
IO Exception callback: attempt 0
IO Exception callback: attempt 1
IO Exception callback: attempt 2
Attempts exhausted. Total: 3
Last exception: Test IO Exception

As we can see, only IOException initiated three attempts. Note that the attempts are numbered from 0 because when the callback is executed the attempt is not exhausted, so the last attempt has #2 and not #3. But on RecoveryCallback all the attempts are exhausted, so the context holds 3 attempts.

We can also see that the RecoveryCallback isn’t called when the attempts were a success. That is, it is only called when the execution ended with an exception.

The RetryTemplate is synchronous, so all the execution happens in our main thread. That is why I added try/catch blocks around the calls, to allow the program run all three examples without a problem. Otherwise the retry policy would rethrow the exception after its last unsuccessful attempt and would stop the execution.

There is also a very interesting CompositeRetryPolicy which allows to add several policies and delegates to call them in order, one by one. It can also allow to create quite a flexible retry strategy, but that is another topic in itself.

I think that spring-retry is a very useful library which allows to make common retryable tasks more predictable, testable and easier to implement.

About Maryna Cherniavska I have productively spent 10+ years in IT industry, designing, developing, building and deploying desktop and web applications, designing database structures and otherwise proving that females have a place among software developers. And this is a good place.