Arvutiteaduse instituut
  1. Kursused
  2. 2024/25 kevad
  3. Ettevõttesüsteemide integreerimine (MTAT.03.229)
EN
Logi sisse

Ettevõttesüsteemide integreerimine 2024/25 kevad

  • Home
  • Lectures
  • Practicals
  • Assignements
  • Project and exam
  • Message Board

Session 6.2: Resilient microservices patterns

You will use the project you cloned for this session (same as Session 6.1)

If you want to create a new Spring Boot project that implements resilient microservices patterns from scratch, you need to install the following dependencies for both the Product and Inventory services:

  • Spring Web
  • Resilience4j
  • starter actuator
  • aop

For the last, you may need to add it manually

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

Implementing the Circuit Breaker pattern

We will implement a circuit breaker for the request from the product-service to inventory-service. A simple diagram of implementing the circuit breaker is shown in the following figure:

To keep the code changes traceable and facilitate the comprehension of the circuit breaker pattern, we have created a new request handler in ProductController.java, to which we have applied the @CircuitBreaker annotation and we have also defined a corresponding fallback method that returns a default object in case the request fails.

...
// --------------------------------  Circuit Breaker
/*
@GetMapping("/products/quantityCB/{id}")
@CircuitBreaker(name = "inventory", fallbackMethod = "fallbackQuantityCB")
public Optional<ProductQuantityDto>  getProductWithQuantityDelay(@PathVariable String id){
return  productService.getProductWithQuantityCB(id);
}

public Optional<ProductQuantityDto>  fallbackQuantityCB(Exception e) {
    log.info("We are not able to fetch the quality of the product");
    return  Optional.of(new ProductQuantityDto("00", "p-000-00", "type of product", "description of product", BigDecimal.valueOf(0), 0 ));
} 
*/
// --------------------------------  Circuit Breaker
...

We have also defined a new function to handle it in ProductService.java. It is the same as the getProductWithQuantity function.

...
// --------------------------------  Circuit Breaker
/*
 public   Optional<ProductQuantityDto>  getProductWithQuantityCB(String id){
 Optional<Product> product =  productRepository.findById(id);
 return product.map(this::mapToProductQuantityDto);
*/
// --------------------------------  Circuit Breaker
...

1. Uncomment the aforementioned request handler in ProductController.java and the function in ProductService.java.

2. Check the configuration of the circuit breaker in the application.properties of the product-service. They are annotated to facilitate your understanding.

3. Run all your services if they are not already running, you also need to rerun the product-service since it was modified.

4. Visit http://localhost:8761/ to make sure that your services are running and requested with Eureka.

5. Send the following requests, in RestClientFile.rest. The first will invoke a request handler that does not implement a circuit breaker, but the second is implementing a circuit breaker to be activated in case the request fails. However, since the inventory-service is running and the request will not fail, both of these requests should work and return the same result.

### Get a product with quantity no CB -> produce exception
GET http://localhost:8082/api/products/quantity/01

### Get a product with quantity with CB returns the default response
GET http://localhost:8082/api/products/quantityCB/01

Note: if your API is running and the route to both product-service and inventory-service are registered with it, you can use the 8080 port instead of 8082.

6. Visit http://localhost:8082/actuator/health to check the status of your circuit breaker. It should be CLOSED (working normally).

7. Stop the inventory-service, and now any request to it should fail.

8. Resend the following request, the request will fail, which will trigger the fallback function and returns the default message in case of failure. We are using a default object for that instead of sending a string message.

### Get a product with quantity with CB returns the default response
GET http://localhost:8082/api/products/quantityCB/01

9. Visit http://localhost:8082/actuator/health to check the status of your circuit breaker. Did its status change? How many requests do we need to send to change its status to OPEN/HALF_OPEN? Try to send the same request several times and monitor its status by visiting http://localhost:8082/actuator/health (you need to refresh the page).

10. Resend the following request, just to compare how your application will respond when you do not use a circuit breaker for requests that may fail.

### Get a product with quantity no CB -> produce exception
GET http://localhost:8082/api/products/quantity/01 

11. Rerun the inventory-service and wait 30 seconds until it registers itself with Eureka.

12. Resend the following request, how many requests do we need to send to change its status to CLOSED?

### Get a product with quantity with CB returns the default response
GET http://localhost:8082/api/products/quantityCB/01

Implementing the Time Limiter pattern

Unlike the Circuit Breaker pattern, the time limiter pattern will not wait for the request to fail, but it will wait a defined time until it terminates the request and triggers a fallback method.

1. Comment out the request handler in ProductController.java and the function in ProductService.java related to the Circuit Breaker, and uncomment the request handler in ProductController.java and the function in ProductService.java related to the Circuit Breaker and TimeLimiter.

2. Check the code of the request handler and its associated function, it is annotated.

3. Check the configuration of the TimeLimiter in the application.properties of the product-service.

4. Run all your services if they are not already running, you also need to rerun the product-service since it was modified.

5. Resend the following request, the request will not fail this time but it will be terminated by the TimeLimiter and the fallback function will be triggered, which will return the default object.

### Get a product with quantity with CB returns the default response
GET http://localhost:8082/api/products/quantityCB/01

Implementing the Retry pattern

1. Check the configurations of the Retry in the application.properties of the product-service.

2. Comment out the request handler in ProductController.java related to the Circuit Breaker + TimeLimiter, and uncomment the request handler in ProductController.java related to Retry. You can use the same function in ProductService.java for Retry, i.e., you do not need to modify anything in ProductService.java for this step.

3. Run all your services if they are not already running, you also need to rerun the product-service since it was modified.

4. Send the following request, and keep your eyes on the terminal of the products-service, which will show the number of retry attempts and the time they were triggered.

### Get a product with quantity with CB returns the default response
GET http://localhost:8082/api/products/quantityCB/01

Implementing the Rate Limiter pattern

1. Check the configurations of the Rate Limiter pattern in the application.properties of the product-service.

2. Comment out the request handler in ProductController.java related to Retry, and uncomment the request handler in ProductController.java related to Rate Limiter. Comment out the Thread.sleep(8000); in the function in ProductService.java, as follows:

  public   Optional<ProductQuantityDto>  getProductWithQuantityCB(String id){
            Optional<Product> product =  productRepository.findById(id);
            //Thread.sleep(8000); // just to cause a delay of 8 seconds
            return product.map(this::mapToProductQuantityDto);
            }

3. Run all your services if they are not already running, you also need to rerun the product-service since it was modified.

4. Send the following request several times, and keep your eyes on the terminal, which will show that only two requests can be sent within 5 seconds. Then, you have to wait for the next time period (also 5 seconds) to start to be able to send the request again.

### Get a product with quantity with CB returns the default response
GET http://localhost:8082/api/products/quantityCB/01
  • Arvutiteaduse instituut
  • Loodus- ja täppisteaduste valdkond
  • Tartu Ülikool
Tehniliste probleemide või küsimuste korral kirjuta:

Kursuse sisu ja korralduslike küsimustega pöörduge kursuse korraldajate poole.
Õppematerjalide varalised autoriõigused kuuluvad Tartu Ülikoolile. Õppematerjalide kasutamine on lubatud autoriõiguse seaduses ettenähtud teose vaba kasutamise eesmärkidel ja tingimustel. Õppematerjalide kasutamisel on kasutaja kohustatud viitama õppematerjalide autorile.
Õppematerjalide kasutamine muudel eesmärkidel on lubatud ainult Tartu Ülikooli eelneval kirjalikul nõusolekul.
Courses’i keskkonna kasutustingimused