DEV Community

nk sk
nk sk

Posted on

🌐 Mini Project: Async Product Service with `CompletableFuture`

Scenario:

We’re building a service that fetches:

  1. Product details (takes ~1s)
  2. Pricing info (takes ~2s, sometimes slow → use timeout & fallback)
  3. Reviews (parallel fetch, then combine)

Finally, we combine everything into a single response string.


✅ Full Example Code

import java.util.concurrent.*;

public class AsyncProductService {

    private static final ExecutorService executor = Executors.newFixedThreadPool(5);

    public static void main(String[] args) throws Exception {

        // Step 1: Fetch product details
        CompletableFuture<String> productFuture = CompletableFuture.supplyAsync(() -> {
            sleep(1000);
            return "Product: Laptop";
        }, executor);

        // Step 2: Fetch price (with timeout + fallback)
        CompletableFuture<String> priceFuture = CompletableFuture.supplyAsync(() -> {
            sleep(3000); // simulate slow API
            return "Price: $1200";
        }, executor)
        .completeOnTimeout("Price: unavailable (timeout fallback)", 2, TimeUnit.SECONDS)
        .exceptionally(ex -> "Price: unavailable (error fallback)");

        // Step 3: Fetch reviews (parallel task)
        CompletableFuture<String> reviewsFuture = CompletableFuture.supplyAsync(() -> {
            sleep(1500);
            return "Reviews: ⭐⭐⭐⭐";
        }, executor);

        // Step 4: Combine product + price first
        CompletableFuture<String> productWithPrice =
                productFuture.thenCombine(priceFuture, (product, price) -> product + ", " + price);

        // Step 5: Add reviews to final response
        CompletableFuture<String> finalResponse =
                productWithPrice.thenCombine(reviewsFuture, (partial, reviews) -> partial + ", " + reviews);

        // Step 6: Wait and print final result
        System.out.println("Final Response: " + finalResponse.get());

        executor.shutdown();
    }

    private static void sleep(int ms) {
        try { Thread.sleep(ms); } catch (InterruptedException e) {}
    }
}
Enter fullscreen mode Exit fullscreen mode

📝 Example Output

Final Response: Product: Laptop, Price: unavailable (timeout fallback), Reviews: ⭐⭐⭐⭐
Enter fullscreen mode Exit fullscreen mode

(or, if price API responds in time:)

Final Response: Product: Laptop, Price: $1200, Reviews: ⭐⭐⭐⭐
Enter fullscreen mode Exit fullscreen mode

⚡ Key Concepts Demonstrated

  • Parallel ExecutionsupplyAsync + thenCombine
  • Dependent Pipelines → product first, then combine with price & reviews
  • ResiliencecompleteOnTimeout & exceptionally
  • Thread Control → custom executor with 5 threads
  • Final Aggregation → all tasks merged into one CompletableFuture

✅ This pattern is very close to real-world microservices aggregation, e.g., an API Gateway calling multiple services in parallel, handling timeouts gracefully, and returning a combined response.


Top comments (0)