spring

How to Use Spring Retry Template

Welcome readers, in this tutorial, we will see the retry mechanism in a simple spring boot application.

1. Introduction

Before going further in this tutorial we will take a look at the common terminology such as introduction to Spring Boot, and Retry mechanism in spring framework.

1.1 What is Spring boot?

  • Spring boot is a module that provides rapid application development feature to the spring framework including auto-configuration, standalone-code, and production-ready code
  • It creates applications that are packaged as jar and are directly started using embedded servlet container (such as Tomcat, Jetty or Undertow). Thus, no need to deploy the war files
  • It simplifies the maven configuration by providing the starter template and helps to resolve the dependency conflicts. It automatically identifies the required dependencies and imports them in the application
  • It helps in removing the boilerplate code, extra annotations, and XML configurations
  • It provides a powerful batch processing and manages the rest endpoints
  • It provides an efficient JPA-starter library to effectively connect the application with the relational databases
  • It offers a Microservice architecture and cloud configuration that manages all the application related configuration properties in a centralized manner.

1.2 What is the Retry mechanism in Spring boot?

Before we start, let us first understand a few basics about the Retry pattern

  • A retry is used only if you think that it may meet your use case and should NOT be used for every use case
  • The retry may cause resource clogging and sometimes make things even worse. Therefore the retries have to be limited
  • A retry should not be done for every exception. It should always be coded for a specific exception type like SQLException.class, TimeoutException.class etc
  • A retry can cause multiple threads trying to access the same shared resource and hence locking can be an issue
  • Retry mechanism should take care of idempotency i.e. triggering the same request should not trigger a duplicate transaction
Spring Retry diagram
Fig. 1: Retry mechanism diagram

The Spring Retry mechanism is used to add retry logic to a spring application and is not probably well known because it is not listed on the Spring documentation overview. This mechanism offers features like –

  • Based on the Exception
  • Back off time
  • Graceful handle

Now let us create a simple example to showcase the retry mechanism in the spring application. But before going any further I’m assuming that readers are aware of the concepts of creating and running a basic spring boot application.

2. How to use Spring Retry Template

Here is a systematic guide for implementing this tutorial.

2.1 Tools Used and Project Structure

We are using Eclipse, JDK 8, and Maven. In case you’re confused about where you should create the corresponding files or folder, let us review the project structure of the spring boot application.

Spring Retry - Project structure
Fig. 2: Project structure

Let us start building the application!

3. Creating a Spring boot application

Below are the steps involved in developing the application.

3.1 Maven Dependency

Here, we specify the dependency for the Spring boot and Spring retry. Maven will automatically resolve the other dependencies. The updated file will have the following code.

pom.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version="1.0" encoding="UTF-8"?>
    <modelVersion>4.0.0</modelVersion>
     
    <groupId>com.spring.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>tbp-spring-retry</name>
    <description>Demo project for retry in springboot</description>
     
     
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
    </parent>
     
    <properties>
        <java.version>1.8</java.version>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>

3.2 Application Properties file

Create a new properties file at the location: spring-retry/src/main/resources/ and add the application configuration to this file.

application.properties

1
2
# Application server port
server.port=9098

3.3 Java Classes

Let us write all the java classes involved in this application.

3.3.1 Implementation/Main class

Add the following code to the main class to bootstrap the application from the main method and enable the retry mechanism in the application.

SpringRetryApplication.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
package com.spring.retry;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.retry.annotation.EnableRetry;
 
// Main implementation class which serves two purposes in a spring boot application: Configuration and bootstrapping.
@SpringBootApplication
// To enable spring retry in spring boot project.
@EnableRetry
public class SpringRetryApplication {
     
    private static final Logger LOGGER = LoggerFactory.getLogger(SpringRetryApplication.class);
 
    public static void main(String[] args) {
        SpringApplication.run(SpringRetryApplication.class, args);
        LOGGER.info("SpringRetryApplication application started successfully.");
    }
}

3.3.2 Service class

Add the following code to the service class that has the invoke(……) method to talk to a 3rd party service. In case the 3rd party service does not respond due to any XYZ reason, the invoke(……) method will attempt three retries. If the response is not received during these retries, the exception will be thrown and the exception fallback method (i.e. recover(……)) would be invoked. Thus this fallback method will then send a response to the user.

SocialSecurityService.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.spring.retry.service;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
 
@Service
public class SocialSecurityService {
 
    private static final Logger LOGGER = LoggerFactory.getLogger(SocialSecurityService.class);
 
    int counter = 1;
 
    // To indicate any method to be a candidate of retry.
    // 'maxAttempts' attribute tells that how many times we would need to retry the 3rd party service to fetch the details.
    // 'value' attribute tells the type of exceptions (e.g. TimeoutException, IOException, etc.) that we can happen when retry takes place.
    // 'backoff' attribute tells to create a gap between the retries.
    @Retryable(maxAttempts = 3, value = { RuntimeException.class }, backoff = @Backoff(delay = 2000, multiplier = 2))
    public String invoke(final String ssn) {
        // For simplicity we are returning the user-input. In ideal scenario it will call the
        // social-security service to fetch the details.
        // return ssn;      // As we are showing the retry mechanism in this tutorial, we will comment this to assume that the 3rd-party service is down.
 
 
        // So to perform this retry mechanism we'll throw some dummy exception
        // (considering the 3rd-party service is down and throwing an exception).
        LOGGER.info("Executed counter= {}.", counter);
        // This counter will help us to understand that after 3 retry attempts the fallback method would be called.
        counter++;
        throw new RuntimeException("Some random Exception");
    }
 
    // To specify the fallback method.
    // The exception in this method should match the exception defined in the @Retryable annotation.
    @Recover
    public String recover(final RuntimeException e, final String ssn) {
        LOGGER.info("Sending the fall-back method response to the user as the number of max-attempts for the "
                + "3rd-party service has been reached.");
        return "Not able to connect to the social security details portal at this time.";
    }
}

3.3.3 Controller class

Add the following code to the controller class designed to handle the incoming requests. The class is annotated with the @RestController annotation where every method returns a domain object as a JSON response instead of a view.

SocialSecurityController.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.spring.retry.controller;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
 
import com.spring.retry.service.SocialSecurityService;
 
@RestController
public class SocialSecurityController {
     
    private static final Logger LOGGER = LoggerFactory.getLogger(SocialSecurityController.class);
     
    @Autowired
    SocialSecurityService socialSecurityService;
           
          // Sample url- http://localhost:9098/getssn?ssn=1234
    @GetMapping(value = "/getssn", consumes = "application/json", produces = "application/json")
    public String getSocialSecurityDetails(@RequestParam(value = "ssn") String ssn) {
        LOGGER.info("Invoking the service with ssn= {}.", ssn);
        return socialSecurityService.invoke(ssn);
    }
}

4. Run the Application

To execute the application, right-click on the SpringRetryApplication.java class, Run As -> Java Application.

Spring Retry - Run the Application
Fig. 3: Run the Application

5. Project Demo

Open the Postman tool or any browser of your choice and hit the following URLs to display the fallback response from the service.

1
2
// Get the social security details for a social security number

Now on hitting this URL you will get the fallback response after the retry limit is exceeded (while waiting for a response from the 3rd party service) and the same can be verified from the logs shown below.

1
2
3
4
5
2020-07-11 17:05:53.050  INFO 17880 --- [nio-9098-exec-1] c.s.r.c.SocialSecurityController         : Invoking the service with ssn= 1234.
2020-07-11 17:05:53.106  INFO 17880 --- [nio-9098-exec-1] c.s.retry.service.SocialSecurityService  : Executed counter= 1.
2020-07-11 17:05:55.108  INFO 17880 --- [nio-9098-exec-1] c.s.retry.service.SocialSecurityService  : Executed counter= 2.
2020-07-11 17:05:59.109  INFO 17880 --- [nio-9098-exec-1] c.s.retry.service.SocialSecurityService  : Executed counter= 3.
2020-07-11 17:05:59.111  INFO 17880 --- [nio-9098-exec-1] c.s.retry.service.SocialSecurityService  : Sending the fall-back method response to the user as the number of max-attempts for the 3rd-party service has been reached.

That is all for this tutorial and I hope the article served you whatever you were looking for. Happy Learning and do not forget to share!

6. Summary

In this section, we learned:

  • Spring Boot and Retry mechanism
  • Steps to implement the retry mechanism in spring boot application

You can download the sample application as an Eclipse project in the Downloads section.

7. Download the Eclipse Project

This was an example of a Retry mechanism in a Spring boot application.

Download
You can download the full source code of this example here: How to use Spring Retry Template

Yatin

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Rodney Barbati
Rodney Barbati
3 years ago

Unfortunately, although the title of the article is “How to use Spring Retry Template”, the example code does not in fact use a RetryTemplate.

Back to top button