Careeroza
Real World Example
Order Placed in a Modular Monolith
Zomato, Swiggy and many startups begin as a modular monolith: one Spring Boot app with clear modules (orders, payments, notifications, loyalty). Events keep modules independent, so a module can later move into its own microservice and the event becomes a Kafka message.
// orders module
@Transactional
public OrderResponse placeOrder(PlaceOrderRequest req) {
Order order = orders.save(Order.from(req));
stockService.reserve(order); // throws if out of stock -> rollback
events.publishEvent(new OrderPlacedEvent(order.getId(), req.userId(), order.getTotal()));
return OrderResponse.from(order);
}
// notifications module
@Async
@TransactionalEventListener
public void notifyCustomer(OrderPlacedEvent e) { smsClient.send(e.userId(), "Order " + e.orderId() + " placed!"); }
// loyalty module
@TransactionalEventListener
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addPoints(OrderPlacedEvent e) { loyalty.add(e.userId(), e.total().intValue() / 100); }Example
Success and failure cases:
curl -X POST localhost:8080/api/orders -d '{"userId":7,"items":[{"productId":3,"quantity":1}]}' -H "Content-Type: application/json"
curl -X POST localhost:8080/api/orders -d '{"userId":7,"items":[{"productId":3,"quantity":500}]}' -H "Content-Type: application/json"Example output
HTTP/1.1 201 Created {"orderId":1001,"status":"PLACED"}
INFO notifications : SMS sent for order 1001
INFO loyalty : user 7 +549 points
HTTP/1.1 409 Conflict {"title":"Out of stock","detail":"Only 11 units of product 3 left"}
(no SMS, no points: the transaction rolled back, so no listener ran)