Lejdi Prifti

0 %
Lejdi Prifti
Software Engineer
Web3 Developer
ML Practitioner
  • Residence:
    Albania
  • City:
    Tirana
  • Email:
    info@lejdiprifti.com
English
Italian
French
Spring
React & Angular
Machine Learning
Docker & Kubernetes
AWS & Cloud
Team Player
Communication
Time Management
  • Java, JavaScript, Python
  • AWS, Kubernetes, Azure
  • Bootstrap, Materialize
  • Stylus, Sass, Less
  • Blockchain, Ethereum, Solidity
  • React, React Native, Flutter
  • GIT knowledge
  • Machine Learning, Deep Learning
0

No products in the basket.

Use Spring Retry instead of do-while

1. November 2023

In this article, I’ll outline the advantages of switching from the standard do-while method to Spring Retry when contacting external services.

Consider the following situation. The source and target microservices are our two. To begin processing its own data, the source microservice needs to get in touch with the target microservice to find out if the data is ready. The data readiness procedure is time-consuming, therefore we are unsure of when it will be finished. Let’s assume that, among a plethora of possible design solutions to this type of issue, we opted to verify the data ready state by a straightforward HTTP request.

Our target microservice includes a very simple logic. It basically defines an endpoint /readiness that based on the number of attemps either throws an exception or returns OK .

				
					@Slf4j
@RestController
@RequestMapping("/target")
public class TargetController {

 private static int NUMBER_OF_ATTEMPTS = 0;

 @GetMapping("/readiness")
 public String isDataReady() throws Exception {
  if (NUMBER_OF_ATTEMPTS < 5) {
   NUMBER_OF_ATTEMPTS++;
   throw new Exception("data is not ready");
  }
  log.info("data is ready");
  NUMBER_OF_ATTEMPTS = 0;
  return "OK";
 }

}
				
			

Now, let’s have a look at the source microservice. It defines a service called ExternalService which makes the call to the target microservices for getting the information needed. The method checkWithDoWhile makes an HTTP call using RestTemplate to the target microservice and returns the body if the request goes well. Otherwise, it catches the exception thrown and puts the thread to sleep in order to give time to the target microservice to finish making the data ready. If you look at the code, it is confusing. 

				
					@Slf4j
@Service
public class ExternalService {

 static final String URL = "http://localhost:8081/target/readiness";

 @Autowired
 private RestTemplate restTemplate;

 public String checkWithDoWhile() {
  long timeToWait = 1000;
  int numRetry = 1;
  int maxAttempts = 10;
  boolean isDataReady = false;
  String readiness = null;
  do {
   log.info("tentative num: " + numRetry + " for getting the readiness of data from external service");
   try {
    HttpEntity<?> entity = new HttpEntity<Object>(null, null);
    ResponseEntity<String> response = restTemplate.exchange(URL, HttpMethod.GET, entity, String.class);
    readiness = response.getBody();
    isDataReady = true;
   } catch (Exception e) {
    try {
     Thread.sleep(timeToWait);
    } catch (InterruptedException exception) {
     log.error(e.getMessage());
    }
    numRetry++;
   }
  } while (!isDataReady && numRetry <= maxAttempts);
  return readiness;
 }
}
				
			

Now, let’s look at how you can accomplish the same thing using Spring Retry.

				
					@Slf4j
@Service
public class ExternalService {

 static final String URL = "http://localhost:8081/target/readiness";

 @Autowired
 private RestTemplate restTemplate;

 @Retryable(retryFor = Exception.class, maxAttempts = 10, backoff = @Backoff(delay = 1000))
 public String checkWithRetry() {
  HttpEntity<?> entity = new HttpEntity<Object>(null, null);
  ResponseEntity<String> response = restTemplate.exchange(URL, HttpMethod.GET, entity, String.class);
  return response.getBody();
 }

}
				
			

The @Retryable annotation is used to specify that the method should be retried in case of exceptions. It specifies the following attributes:

  • retryFor = Exception.class: This means the method should be retried for any exception type.
  • maxAttempts = 10: It specifies a maximum of 10 retry attempts.
  • backoff = @Backoff(delay = 1000): It sets a backoff period of 1000 milliseconds (1 second) between retries.

Simple and clean. Use it!

In order to use Spring Retry, you need the following dependencies.

				
					<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
</dependency>
				
			

Additionally, Spring Retry must be activated in the Configuration class using @EnableRetry annotation.

				
					@EnableRetry
@Configuration
public class CommonConfig {

 @Bean
 public RestTemplate restTemplate() {
  return new RestTemplate();
 }
}    
				
			

Check the repository for the full working example: https://github.com/lejdiprifti/medium

Buy Me A Coffee
Posted in SpringBootTags:
Write a comment