Handling Concurrent Service Calls in a Spring Boot Application: CompletableFuture and @Async

  • 4.2/5
  • 489
  • Nov 16, 2024

In modern e-commerce applications, service endpoints often need to consolidate data from multiple sources. Imagine an API to retrieve an order summary, gathering details from services like order-service, customer-service, and inventory-service, along with a local method call for payment details.

Efficient handling of these concurrent calls is crucial for performance, and Spring Boot offers two primary approaches: asynchronous programming using CompletableFuture (for Spring MVC) and reactive programming using WebClient (for Spring WebFlux).

Here, we explore CompletableFuture approach, highlighting the advantages and implementations in a Spring Boot e-commerce context.

Asynchronous Programming with CompletableFuture and @Async in Spring Web

This approach leverages the @Async annotation and ompletableFuture to make asynchronous calls to the order-service, customer-service, and inventory-service in a Spring Web application.

1) Enable Async Support

First, ensure that your Spring Boot application is configured to support asynchronous processing by adding @EnableAsync in the main application class.

2) Create Client classes

In these service classes, we will make asynchronous HTTP calls to the order-service, customer-service, and inventory-service.

3) Internal method call for Payment Info

This PaymentService demonstrates an internal call to calculate payment logic. It introduces a 500-millisecond delay to simulate the time it might take to fetch or calculate payment data from an external system or database.

4) Create a order aggregation service class

This service will call the asynchronous service clients and consolidate the results.

5) Create a order aggregation controller class

In your controller, call aggregateOrderData and return the result.

6) Add external services URLs in application.properties

These are the external service URLs to be used in the respective client to call endpoints.

7) Create "order-service", "customer-service", and "inventory-service"

These are really simple Spring Boot services with only one endpoint, so there is no point in discussing them in detail. Please find below the repo link for them.

1) The order-service

Repo link: GitHub

Swagger: http://localhost:8081/swagger-ui.html

2) The customer-service

Repo link: GitHub

Swagger: http://localhost:8082/swagger-ui.html

3) The inventory-service

Repo link: GitHub

Swagger: http://localhost:8083/swagger-ui.html

Each service has one endpoint that simulates a delay by using Thread.sleep().

8) Test the application

Run your Spring Boot application and navigate to http://localhost:8080/swagger-ui/ to access the Swagger UI. This will allow you to test your endpoints interactively.

2024-11-11T18:18:14.343+05:30 INFO 6942 --- [concurrent-service-calls-spring-boot-completable-future] [nio-8080-exec-5] com.cb.controller.OrderController : Fetching order summary for order id: 560ac632-bee9-4322-b204-c4f77e0e2adc, customer id: 77f67c24-19af-4f85-b9d1-561a2afe47e7, product id: 4eea9612-0c17-4ce3-9fd7-689d7b9c01b9
2024-11-11T18:18:14.359+05:30 INFO 6942 --- [concurrent-service-calls-spring-boot-completable-future] [ task-1] com.cb.client.order.OrderClient : Fetching order from order service for order id: 560ac632-bee9-4322-b204-c4f77e0e2adc
2024-11-11T18:18:14.359+05:30 INFO 6942 --- [concurrent-service-calls-spring-boot-completable-future] [ task-2] com.cb.client.customer.CustomerClient : Fetching customer from customer service for customer id: 77f67c24-19af-4f85-b9d1-561a2afe47e7
2024-11-11T18:18:14.359+05:30 INFO 6942 --- [concurrent-service-calls-spring-boot-completable-future] [ task-3] c.cb.client.inventory.InventoryClient : Fetching inventory from inventory service for product id: 4eea9612-0c17-4ce3-9fd7-689d7b9c01b9
2024-11-11T18:18:14.931+05:30 INFO 6942 --- [concurrent-service-calls-spring-boot-completable-future] [ task-3] c.cb.client.inventory.InventoryClient : Inventory fetched successfully for product id: 4eea9612-0c17-4ce3-9fd7-689d7b9c01b9
2024-11-11T18:18:14.931+05:30 INFO 6942 --- [concurrent-service-calls-spring-boot-completable-future] [ task-2] com.cb.client.customer.CustomerClient : Customer fetched successfully for customer id: 77f67c24-19af-4f85-b9d1-561a2afe47e7
2024-11-11T18:18:14.931+05:30 INFO 6942 --- [concurrent-service-calls-spring-boot-completable-future] [ task-1] com.cb.client.order.OrderClient : Order fetched successfully for order id: 560ac632-bee9-4322-b204-c4f77e0e2adc
2024-11-11T18:18:14.932+05:30 INFO 6942 --- [concurrent-service-calls-spring-boot-completable-future] [ task-1] com.cb.controller.OrderController : Order summary fetched successfully for order id: 560ac632-bee9-4322-b204-c4f77e0e2adc, customer id: 77f67c24-19af-4f85-b9d1-561a2afe47e7, product id: 4eea9612-0c17-4ce3-9fd7-689d7b9c01b9 in 590 ms

From the logs, you can see that the entire process took approximately 600 ms. Without parallel calls, it would have taken more than 2000 ms, with about 500 ms for each external service call as well as one internal method call.

Source code: GitHub

Index
How to Implement PostgreSQL Full-Text Search with Spring Boot

15 min

Spring's transaction management with the @Transactional annotation

9 min

Spring Boot Rest APIs with PostgreSQL (Spring Boot + Rest APIs)

15 min

Caching in Spring Boot (@Cacheable, @CacheEvict & @CachePut)

21 min

Declarative REST Client in Spring Boot (Spring 6 HTTP Interface)

13 min

Circuit Breaker in Spring Boot (Spring Cloud Circuit Breaker + Resilience4j)

12 min

Handling Concurrent Service Calls in a Spring Boot Application: Asynchronous vs. Reactive Approaches

11 min

Profiling a Spring Boot application with Pyroscope

7 min

Service discovery in Spring Boot (Spring Cloud + Netflix Eureka)

9 min

Dockerize Spring Boot app and Push image to DockerHub (Spring Boot + DockerHub)

4 min

Creating a Jenkins Pipeline for Spring Boot application

2 min

Monitoring Microservices (Spring Boot + Micrometer + Prometheus + Grafana)

7 min

Edge Server Pattern in Microservices (Spring Cloud Gateway)

7 min

Circuit Breaker Pattern in Microservices (Spring BOOT + Resilience4j)

4 min

Spring Cloud config server setup with Git

8 min

Distributed Tracing in Microservices (Spring Cloud Sleuth + Zipkin)

9 min

Circuit Breaker Pattern with Resilience4J in a Spring Boot Application

24 min

Deploying Spring Boot microservices on Kubernetes Cluster

12 min

Reactive programming in Java with Project Reactor

50 min

Spring Reactive with PostgreSQL (Spring Boot WebFlux + PostgreSQL)

13 min

Spring Reactive, Thymeleaf Hello World (Spring Webflux + Thymeleaf + JS/CSS)

9 min

Problem JSON (application/problem+json) in Spring WebFlux

15 min

Spring Boot Login/Logout (Spring Security + MySql + Thymeleaf)

21 min

Securing Server-to-Server Communication with "Spring Boot" & "OAuth 2"

18 min

Integrating Elasticsearch with a Spring Boot and PostgreSQL application

16 min

Sending Emails in Spring Boot via SMTP

7 min

How to create a basic Spring 6 project using Maven

5 min

Spring Boot, Thymeleaf Hello World (Spring Boot + Thymeleaf + JS/CSS)

9 min