Spring Boot integrated Spring Retry quick start Demo

HBLOG
3 min readApr 3, 2024

--

1.Retry introduction

Spring Retry

It provides the ability to automatically re-invoke failed operations. This is useful in situations where the error may be temporary (such as a transient network failure). Starting from version 2.2.0, the retry function has been withdrawn from Spring Batch and became a new independent library: Spring Retry

scenes to be used

In the daily development process, it is inevitable that there will be interactions with third-party interfaces, such as text message sending, remote service calls, lock competition, etc. When normal calls are abnormal, such as network jitters, these intermittent abnormalities will occur for a period of time. It will recover on its own after that. In order for the program to be more robust and less prone to failures, business operations need to be retriggered to prevent intermittent exceptions from affecting program performance.

tips:Idempotence

Be careful when using retries in non-idempotent situations. The definition of idempotence in HTTP/1.1 is: one and multiple requests for a resource should have the same result for the resource itself (except for problems such as network timeout). In other words, any multiple executions have the same impact on the resource itself as one execution.

2.Code Project

Experimental goal: simulate three-party interface exceptions and trigger retries

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springboot-demo</artifactId>
<groupId>com.et</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>SpringRetry</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--retry-->
<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>
</project>

application.yaml

server:
port: 8088

RemoteApiService.java

  • @RetryableNote, the value value indicates which exceptions trigger retries, maxAttempts indicates the maximum number of retries, the default is 3, delay indicates the delay time of retry, and multiplier indicates that the last delay time is a multiple of this time.
  • @RecoverNote: when the number of retries reaches the set number, an exception will still be thrown and the callback function will be executed.
package com.et.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;
import java.time.LocalDateTime;
import java.time.LocalTime;
@Service
public class RemoteApiService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 1.5))
public boolean pay(int num) throws Exception{
logger.info("invoke third method");
logger.info("do something... {}", LocalDateTime.now());
//mock exception
if(num==0) {
throw new Exception("error,need retry");
}
return true;
}
@Recover
public boolean recover(int num) throws Exception {
logger.info("recover ... {},{}", num, LocalDateTime.now());
return false;
}
}

DemoApplication.java

Add the @EnableRetry annotation to the main class to enable the retry mechanism.

package com.et.retry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.retry.annotation.EnableRetry;
@SpringBootApplication
@EnableRetry
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

The above are just some key codes. For all codes, please see the code repository below.

code repository

3.Test

Below is a test class

package com.et.retry;
import com.et.retry.service.RemoteApiService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class DemoTests {
private Logger log = LoggerFactory.getLogger(getClass());
@Autowired
RemoteApiService remoteApiService;
@Before
public void before() {
log.info("init some data");
}
@After
public void after(){
log.info("clean some data");
}
@Test
public void execute() throws Exception {
log.info("pay result:"+remoteApiService.pay(0));
}
}

Run the test method and the results are as follows

2024-04-03 10:35:54.738 INFO 13096 --- [ main] com.et.retry.DemoTests : init some data
2024-04-03 10:35:54.756 INFO 13096 --- [ main] com.et.retry.service.RemoteApiService : invoke third method
2024-04-03 10:35:54.759 INFO 13096 --- [ main] com.et.retry.service.RemoteApiService : do something... 2024-04-03T10:35:54.758
2024-04-03 10:35:56.766 INFO 13096 --- [ main] com.et.retry.service.RemoteApiService : invoke third method
2024-04-03 10:35:56.766 INFO 13096 --- [ main] com.et.retry.service.RemoteApiService : do something... 2024-04-03T10:35:56.766
2024-04-03 10:35:59.776 INFO 13096 --- [ main] com.et.retry.service.RemoteApiService : invoke third method
2024-04-03 10:35:59.776 INFO 13096 --- [ main] com.et.retry.service.RemoteApiService : do something... 2024-04-03T10:35:59.776
2024-04-03 10:35:59.776 INFO 13096 --- [ main] com.et.retry.service.RemoteApiService : recover ... 0,2024-04-03T10:35:59.776
2024-04-03 10:35:59.776 INFO 13096 --- [ main] com.et.retry.DemoTests : pay result:false
2024-04-03 10:35:59.778 INFO 13096 --- [ main] com.et.retry.DemoTests : clean some data

4.Reference

--

--

HBLOG
HBLOG

Written by HBLOG

talk is cheap ,show me your code

No responses yet