Event-Driven Architecture (EDA) — a design pattern where services communicate by producing and consuming events through a message broker, enabling loose coupling and asynchronous processing.
System Design Context: EDA decouples producers from consumers. A producer publishes an event without knowing who will consume it. This enables independent scaling, fault isolation, and new capabilities without modifying existing services.
Key Concepts:
Kafka — Production Implementation:
1// Event definition2public record OrderCreatedEvent(3 Long orderId,4 Long userId,5 BigDecimal total,6 List<OrderItem> items,7 Instant timestamp8) {}910// Producer with idempotency11@Service12@Slf4j13public class OrderService {1415 private final OrderRepository orderRepo;16 private final KafkaTemplate<String, OrderCreatedEvent> kafkaTemplate;17 private final ObjectMapper objectMapper;1819 @Transactional20 public Order createOrder(CreateOrderRequest request) {21 Order order = Order.create(request);22 Order saved = orderRepo.save(order);2324 OrderCreatedEvent event = new OrderCreatedEvent(25 saved.getId(), saved.getUserId(), saved.getTotal(),26 saved.getItems(), Instant.now());2728 kafkaTemplate.send("order-events", saved.getId().toString(), event)29 .addCallback(30 result -> log.info("Event sent: {}", saved.getId()),31 ex -> log.error("Failed to send event: {}", saved.getId(), ex)32 );33 return saved;34 }35}3637// Consumer with idempotency38@Service39@Slf4j40public class NotificationListener {4142 private final ProcessedEventRepository processedRepo;43 private final EmailService emailService;4445 @KafkaListener(46 topics = "order-events",47 groupId = "notification-service",48 containerFactory = "kafkaListenerContainerFactory"49 )50 public void onOrderCreated(51 @Payload OrderCreatedEvent event,52 @Header(KafkaHeaders.RECEIVED_KEY) String key,53 Acknowledgment ack) {54 String eventId = event.orderId() + "-created";5556 // Idempotency check57 if (processedRepo.existsByEventId(eventId)) {58 log.info("Event already processed: {}", eventId);59 ack.acknowledge();60 return;61 }6263 emailService.sendOrderConfirmation(event.userId(), event.orderId());64 processedRepo.save(new ProcessedEvent(eventId));65 ack.acknowledge();66 }67}
Scaling Patterns:
Common Pitfalls:
Monitoring: