Spring Retry provides the ability to automatically re-invoke a failed operation. This is helpful when errors may be transient in nature. For example, a momentary network glitch, network outage, server down, or deadlock.

You can configure the spring-retry module using annotations. You can define the retry limits, fallback methods, etc.

In this post, you will learn how to use the spring-retry module.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<dependency>
   <groupId>org.springframework.boot</groupId> 
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.3.1</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.9</version>
</dependency>
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <optional>true</optional>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
</dependency>

Spring Retry Example

I will demonstrate a service implementation with a method that throws an exception in case of a failure. In such a case of exception, Spring retries to invoke the method 3 times.

In those 3 retry attempts, if a successful response is received from the method, then the response is returned to the caller. Ese a standard fallback method is called.

Defining the Interface

The code for the RetryService interface is this.

1
2
3
4
5
6
7
package guru.springframework;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
public interface RetryService {
    @Retryable(value = {CustomRetryException.class}, maxAttempts = 3, backoff = @Backoff(200))
    public String retry() throws CustomRetryException;
}

The @Retrayable annotation in Line 8 tells Spring that if we get CustomRetryException from the method call, then the method call should be retried 3 times with an interval of 2 seconds before sending the response.

Note: The value attribute in Line 8 tells Spring retry to act if the method throws CustomRetryException. Also the default value of maxAttempts is 3.

The code for the Implementation class is this.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@Slf4j
@Service
public class RetryServiceImpl implements RetryService {
    @Override
    public String retry() throws CustomRetryException {
        log.info("Throwing CustomRetryException in method retry");
        throw new CustomRetryException("Throw custom exception");
    }
    @Recover
    public String recover(Throwable throwable) {
        log.info("Default Retry servive test");
        return "Error Class :: " + throwable.getClass().getName();
    }
}

In Line 11, the @Recover annotation indicates that if you don’t get any success response after 3 retry, this fallback method will get called.

This is the code for the main class.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package guru.springframework;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.retry.annotation.EnableRetry;
@EnableRetry
@SpringBootApplication
public class SpringRetryApplication {
  public static void main(String[] args) {
    SpringApplication.run(SpringRetryApplication.class, args);
  }
}

You need to add @EnableRetry annotation to enable retry.

Test the Application

The code for the SpringRetryApplicationTest is this.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package guru.springframework;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@Slf4j
@SpringBootTest
public class SpringRetryApplicationTest {
    @Autowired
    RetryService retryService;
    @Test
    public void sampleRetryService() {
        try {
            final String message = retryService.retry();
            log.info("message = " + message);
        } catch (CustomRetryException e) {
            log.error("Error while executing test {}", e.getMessage());
        }
    }
}

On Running the Test case, you will see the following output.

Here we get an exception in the backend and then spring retries the same method 3 times as specified. Also, you get fallback response after the retry limit is reached every time we are throwing CustomRetryException.

Summary

The spring-retry module is very helpful to automatically retry a failed operation by replacing itself with having a loop and breaking it once the limit is reached. This feature also comes in handy when you integrate with external APIs and need a robust fail-safe system that can handle system downtime or network downtime.

You can find the source code of this post here on Github.

Reference https://springframework.guru/retry-in-spring-boot-applications/