Spring

Spring Retry – How to use it ?

 Introduction to Spring Retry :

While writing code for enterprise-level applications, we often interact with many external systems usually via web service call. There is a high possibility of temporary network glitches in the process like momentary loss of connectivity with the server due to high network traffic or any other such self-correcting faults. For such instances, the Spring Retry API comes to our rescue.

It provides a facility to retry the same operation a couple of times. This in-turn reduces the failure rates by eliminating the ones occurring due to minor self-correcting faults in the system.

Maven Dependencies :

To use Spring Retry API in your project, add the below dependency in your POM.

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

Also include Spring AOP in your application as it is used by the Spring Retry API.

<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>

For a Spring Boot Application, use the below starter package for Spring AOP:

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

Enabling Spring Retry :

Once you have added the required dependencies in your POM,  use @EnableRetry annotation in Spring configuration class to enable the use of this API.

@Configuration
@EnableRetry
public class SpringTutorialApplication {
...
}

Spring Retry Annotations :

When trying to implement retry operation, the annotations defined in the library  – @Retryable and @Recover comes handy. It is considered to be a cleaner and more recommended approach.

  1. @Retryable Annotation :
    @Service
    public interface SampleService {
        @Retryable(
          value = { FileNotFoundException.class }, 
          maxAttempts = 2,
          backoff = @Backoff(delay = 5000))
        void retryServiceCall(File file) throws FileNotFoundException;
        ...
    }

    In the above code, retryServiceCall() is the method that will be retried up to 2 times ( as defined in maxAttempts) with a delay of 5ms (as defined in the back-off strategy) if an exception of type FileNotFoundException occurs while executing the method.

    If we specify @Retryable annotation without any attribute definitions, the method will be retried up to 3 times with a gap of 1 second for any exception raised in the method.

  2. @Recover Annotation :
    @Service
    public interface SampleService {
        @Retryable(
          value = { FileNotFoundException.class }, 
          maxAttempts = 2,
          backoff = @Backoff(delay = 5000))
        void retryServiceCall(File file) throws FileNotFoundException;
        ...
        @Recover
        void recoverServiceFailure(FileNotFoundException ex, File file);
    }

    A recovery mechanism can be specified for a particular exception type. This recovery method will be executed when the retry operation fails.

    To achieve it, define another method which would accept the instance of exception type along with other parameters of the method marked @Retryable. Annotate this handler method with @Recover annotation.

Retry Handling using RetryTemplate<T> :

Apart from using the annotations,  an alternate way is to  implement RetryTemplate<T> . This will be needed mostly when attempting to perform a stateful retry operation.

  • Defining RetryTemplate<T> :
    @EnableRetry
    @Configuration
    public class SpringTutorialApplication {
     
      @Bean
      public RetryTemplate retryTemplate() {
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(2);
     
        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        backOffPolicy.setBackOffPeriod(5000); // 5ms
     
        RetryTemplate template = new RetryTemplate();
        template.setRetryPolicy(retryPolicy);
        template.setBackOffPolicy(backOffPolicy);
     
        return template;
      }
       
      // ...
    }

    SimpleRetryPolicy defines the retry policy to use when executing a method.

    FixedBackOffPolicy defines the back-off strategy i.e the delay after which the operation must be retried.

  • Using RetryTemplate :
    @Service
    public class SampleService{
    
      @Autowired
      private RetryTemplate retryTemplate;
    
      public void executeServiceCall(){
        retryTemplate.execute((context) -> { .... });//accepts RetryCallback<T>
      }
    ..
    }

    execute() method of RetryTemplate accepts an implementation of RetryCallback<T>.

    RetryCallback is a Functional Interface and so you can chose to write a lean lambda expression to implement it.  It has a method doWithRetry() which accepts a RetryContext . The business logic to be retried , for instance  –  invoking a service call , will be defined in this lambda expression.

Summary :

Use Spring Retry API to perform a retry operation thereby reducing the failures occurring due to minor temporary network glitches.

The annotations @Retryable and @Recover comes handy when trying to build the retrying logic in our application.

You can alternatively choose to implement RetryTemplate by defining the RetryPolicy and BackOffPolicy.

You can also refer the Github repository of spring-retry to explore more about it here.

2 comments

Have you tried what happens if some exception other than FileNotFoundException occurs? For me it is retrying even when some unspecified exception type is being thrown.

Leave a Comment

Your email address will not be published. Required fields are marked *