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...

Reactive programming in Java with Project Reactor

Reactive programming is a declarative programming paradigm that focuses on building applications that are responsive, resilient, and scalable in the face of modern challenges like concurrency, distributed systems, and asynchronous data streams . Reactive programming provides a set of tools, patterns, and abstractions to handle asynchronous and event-driven programming more effectively. Imperative programming focuses on describing the step-by-step instructions or commands that the computer needs to follow to achieve a specific task. In this paradigm, you explicitly state how to perform each operation and control flow in your code. The emphasis is on "how" the computation should be done. int sum = 0; for (int i = 1; i Declarative programming emphasizes specifying what you want to achieve rather than detailing how to achieve it. You describe the desired outcome or the properties of the result, and the programming language or framework handles the execution detai...