Real World Example

Order Confirmation Fan-Out

When you order on Swiggy or Flipkart, the "Order placed" screen appears instantly, while email, SMS, push notification and invoice PDF arrive a few seconds later. ShopEase does the same: the controller responds after saving the order, and the slow work runs in parallel on a dedicated pool.

@Service
@Slf4j
@RequiredArgsConstructor
public class OrderConfirmationService {
    private final NotificationService notifications;   // methods are @Async("notificationExecutor")
    private final InvoiceService invoices;              // @Async too

    public void confirm(Order order) {
        CompletableFuture<Boolean> email = notifications.sendEmail(order.getUser().getEmail(), order.getId());
        CompletableFuture<Boolean> sms   = notifications.sendSms(order.getUser().getPhone(), "Order " + order.getId() + " confirmed");
        CompletableFuture<String>  pdf   = invoices.generateInvoice(order.getId());

        CompletableFuture.allOf(email, sms, pdf)
            .orTimeout(10, TimeUnit.SECONDS)
            .whenComplete((v, ex) -> {
                if (ex != null) log.warn("Some notifications failed for {}: {}", order.getId(), ex.getMessage());
            });
    }
}

Example

curl -X POST localhost:8080/api/orders -H "Content-Type: application/json" -d '{"userId":7,"items":[{"productId":3,"quantity":1}]}'

Example output

HTTP/1.1 201 Created
{"orderId":1001,"status":"PLACED","total":54999.00}

INFO [notify-1] NotificationService : email sent to [email protected]
INFO [notify-2] NotificationService : sms sent to +91-98XXXXXX21
INFO [notify-3] InvoiceService      : invoice INV-1001.pdf generated

Tip: If a notification must never be lost, write it to a database table or a message queue (Kafka/RabbitMQ) instead of a memory thread pool. See the Microservices material.