Skip to main content

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

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

Comments

Popular posts from this blog

Deploying Spring Boot microservices on Kubernetes Cluster

This article guides you through the deployment of two Spring Boot microservices, namely "order-service" and "inventory-service," on Kubernetes using "MiniKube" . We will establish communication between them, with "order-service" making calls to an endpoint in "inventory-service." Additionally, we will configure "order-service" to be accessible from the local machine's browser . 1) Create Spring Boot microservices The Spring Boot microservices, "order-service" and "inventory-service," have been developed and can be found in this GitHub repository. If you are interested in learning more about creating Spring Boot REST microservices, please refer to this or this (Reactive) link. 2) Build Docker Images The Docker images for both "order-service" and "inventory-service" have already been generated and deployed on DockerHub, as shown below. codeburps/order-service cod...

Circuit Breaker Pattern with Resilience4J in a Spring Boot Application

Read Also: Spring Cloud Circuit Breaker + Resilience4j Resilience4j is a lightweight fault tolerance library that draws inspiration from Netflix Hystrix but is specifically crafted for functional programming. The library offers higher-order functions, known as decorators , designed to augment any functional interface, lambda expression, or method reference with features such as Circuit Breaker, Rate Limiter, Retry, or Bulkhead . These functionalities can be seamlessly integrated within a project, class, or even applied to a single method. It's possible to layer multiple decorators on any functional interface, lambda expression, or method reference, allowing for versatile and customizable fault tolerance. While numerous annotation-based implementations exist online, this article focuses solely on the reactive approach using router predicates and router functions . How Circuit Breaker Pattern works? In general, a circuit breaker functions as an automatic electrical s...

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

Feign , an early declarative REST client, was initially part of the Spring Cloud Netflix stack and later rebranded as Spring Cloud OpenFeign . Before its introduction, crafting HTTP calls using RestTemplate involved repetitive code for each service interaction. With Feign, developers could simply define an interface with method contracts mirroring the service's endpoints. Behind the scenes, proxy magic generated a fully functional HTTP client, eliminating the need for boilerplate code . HTTP Interface (Spring Framework 6) The recent release of Spring Framework 6 integrated this declarative REST client as a native part of the core web framework in the form of the HTTP Interface . All the necessary components reside in the spring-web module, which is a transitive dependency for either the spring-boot-starter-web or spring-boot-starter-webflux modules. Currently, the WebFlux dependency is essential due to the HttpServiceProxyFactory , responsible for client gener...