When working with external APIs or databases, especially cloud databases, a lot of things can go wrong. This is where it is important to consider having retries. Spring Retry can handle this for you in an easy and convenient way. In this article, we are going to look at how Spring Retry can robust your application.

Do I need to implement retry logic?

Not necessarily. However, if you are working with external components outside your network it is definitely worth to consider it, I would almost go as far as saying that it should be a requirement. Even if you are not working with any external components and the database that you use is inside your network I would still argue that it’s worth it, especially if your system is going to be put under load. If you overload your database, you can perform retries with a backoff period, so for example, if the database seems overloaded and times out; then you can have a backoff period for a duration of your choice, for example, starting out at half a second.

Is retries always the way to go?

Definitely not. First of all, it is very crucial that you only perform retries on temporary errors. Performing retries on a permanent error is only going to put negative load on the external component.

Second of all, for some applications it might be better to instead have a circuit breaker. So for example, if an external components fails to return a response, then the circuit breaker is triggered which builds a response from another source, or some default response. But it really depends on the situation. Spring Retry makes it possible to use both, and also gives you the possibility to implement both. So you could for example, perform 1 retry, but if that also fails, then the circuit breaker is triggered which handles the response for the user.

With that out of the way, let me introduce to you Spring Retry.

Spring Retry

I previously wrote an article on retry logic where I had implemented my own library for it. This was fun as a learning project, but let’s be real, it is much better to go with a more popular, well tested and used project.

Spring Retry is an open source Spring Project. The GitHub for the project can be found here. It is a popular project that is used by many other projects such as Spring Batch, Spring Integration, and Spring for Apache Hadoop.

Dependencies

In order to get started with Spring Retry, you will need to add two dependencies. The first, and most obvious being Spring Retry.

<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> <version>1.2.2.RELEASE</version> </dependency>

The second dependency is not as obvious though, and it is quite easy to miss as it’s not really that obvious in the documentation; Spring Retry also requires AOP. If you are using Spring Boot you can use the spring-boot-starter-aop .

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>

If it is a plain Spring Framework project, then you have to add two extra dependencies instead.

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.8</version> </dependency>

Make sure to have a look at maven central for newer versions when you are reading this and adding it to your project.

Let’s get going

With the required dependencies added, it is extremely easy to get started. All we have to do is to annotate our application configuration class like below.

@EnableRetry @SpringBootApplication public class SpringBootApplication { // ... }

And then the methods with @Retryable that we want to perform retries on. By default, it will retry every exception with three attempts with a 1-second delay between the attempts. But this is very easily configurable.

@Service public class DatabaseService { @Retryable(value = {FooException.class, BarException.class}, maxAttempts = 2) public void save(Entity entity) { // save entity to the database } @Recover public void recover(BarException exception) { // recover from BarException } }

This will perform a total of 2 retries if the save method would fail, but only if it fails with either a FooException or a BarException.

The @Recover annotation is used to allow us to run special code to recover when a retryable method fails (after the retries in our case) with a BarException.

As you can see, the annotations are a very convenient and easy way to get started. But what if we don’t want to use annotations?

RetryTemplate

If we for some reason don’t want to use the annotation, we can instead use the RetryTemplate provided by Spring Retry. It is considered a good practice to create a bean from it.

@Bean public RetryTemplate retryTemplate() { SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(); retryPolicy.setMaxAttempts(2); FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy(); backOffPolicy.setBackOffPeriod(2000) // milliseconds RetryTemplate template = new RetryTemplate(); template.setRetryPolicy(retryPolicy); template.setBackOffPolicy(backOffPolicy); return template; }

As any bean, this template can now be injected when you need it.

Final words

We have looked at how Spring Retry can help us make our applications more robust, and we have also discussed a bit on when to use it and when to not. Retries are definitely not always the right option, but in many cases it is extremely useful when you are working with services outside your network and control.

Annotations are an easy way to get started with Spring Retry and it is good enough for many cases. However, if you need more customization there is a RetryTemplate where you easily can configure stuff exactly the way you want it.

Until next time!

Like this: Like Loading...