CodeGym /Courses /Module 5. Spring /Lecture 206: Practice: designing an event-driven architec...

Lecture 206: Practice: designing an event-driven architecture

Module 5. Spring
Level 13 , Lesson 5
Available

In previous lectures we got familiar with Event-Driven Architecture (EDA) — its principles and components. We went over how events create loose coupling between microservices, reduce dependencies and improve scalability. You learned how asynchronous communications work, studied the concepts of producers and subscribers, and understood how message brokers like Kafka, RabbitMQ and ActiveMQ manage data transfer. We also discussed common pitfalls when adopting EDA and best practices for designing it.

Now it's time to apply the theory and try to design an event-driven architecture for a concrete case.


Practical design of an event-driven architecture

Task: the "E-commerce Shop" case

Imagine you need to design the event architecture for an online store. As the system architect, you face tasks like:

  • Order processing, including order status notifications, payment, and delivery.
  • Automatic updating of product availability in the inventory.
  • Sending notifications to users about discounts on their favorite products.
  • Logging all events for analytics (for example, for generating reports).

Our goal is to use an event-driven approach to reduce service coupling and increase fault tolerance.


Step 1: Defining events

The first step is to understand which events happen in the system. An event is a "piece of news" that something happened. For example:

Event Description
OrderPlaced An order was created by a user
OrderPaid The user paid for the order
OrderShipped The order was shipped by the delivery service
InventoryUpdated The quantity of a product in the inventory changed
DiscountCreated A new discount was created that might interest users
UserNotificationSent A notification was sent to the user

Each event has its payload and metadata like creation time, user id, etc.

Step 2: Identify producers and subscribers

Now that we've defined the events, we need to figure out who produces them (producers) and who reacts to them (subscribers).

Event Producer Subscribers
OrderPlaced Order Service Inventory Service, Payment Service
OrderPaid Payment Service Shipping Service, Notification Service
OrderShipped Shipping Service Notification Service
InventoryUpdated Inventory Service Analytics Service, Notification Service
DiscountCreated Admin Service Notification Service
UserNotificationSent Notification Service Analytics Service

Example:

  • When a user creates an order, Order Service publishes an OrderPlaced event. That event is picked up by Inventory Service to decrease stock, and by Payment Service to kick off the payment process.

Step 3: Create the interaction diagram

Let's visualize how services exchange events. Here's a diagram showing interaction via a message broker (for example, Apache Kafka):

User
  ↓
Order Service ──> OrderPlaced ─┬──> Inventory Service (decrease stock)
                               └──> Payment Service (initiate payment)
                                    ↓
                                    Payment Service ──> OrderPaid ─┬──> Shipping Service (ship order)
                                                                   └──> Notification Service (notify user)
                                    ↓
Shipping Service ──> OrderShipped → Notification Service

Step 4: Define event structure

Events should contain useful information for subscribers.

Example structure of the OrderPlaced event:

{
  "eventId": "12345",
  "eventType": "OrderPlaced",
  "timestamp": "2023-10-01T12:34:56Z",
  "payload": {
    "orderId": "7890",
    "userId": "456",
    "orderItems": [
      {
        "productId": "101",
        "quantity": 2
      },
      {
        "productId": "202",
        "quantity": 1
      }
    ],
    "totalPrice": 159.99
  }
}

Consistent structures like this help standardize event handling since subscribers always know what to expect.

Step 5: Model the message broker

For implementing the architecture we'll use Apache Kafka. Each event will be published to its own topic.

Topic Event type Example messages
orders OrderPlaced Data about created orders
payments OrderPaid Data about successful payments
shipping OrderShipped Data about shipped orders
inventory InventoryUpdated Data about inventory changes
notifications UserNotificationSent Data about sent notifications

Exercise: implement a producer and a consumer for the OrderPlaced event

Producer implementation:


// Producer for sending OrderPlaced event to Kafka
@Component
public class OrderEventProducer {

    private final KafkaTemplate<String, String> kafkaTemplate;

    public OrderEventProducer(KafkaTemplate<String, String> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    public void sendOrderPlacedEvent(String orderId, String eventPayload) {
        kafkaTemplate.send("orders", orderId, eventPayload);
        System.out.println("OrderPlaced event sent: " + eventPayload);
    }
}

Consumer implementation:


// Consumer for handling OrderPlaced event
@Component
@KafkaListener(topics = "orders", groupId = "inventory-service")
public class OrderEventConsumer {

    @Autowired
    private InventoryService inventoryService;

    @KafkaHandler
    public void handleOrderPlacedEvent(String message) {
        System.out.println("Received OrderPlaced event: " + message);
        inventoryService.updateInventory(message);
    }
}

Tips for designing an event-driven architecture

  • Minimize dependencies. Each service should be as isolated as possible. For example, Notification Service shouldn't know the internal logic of Order Service.
  • Log events. This helps trace what's happening in the system, especially with asynchronous processing.
  • Define event schemas. Use JSON Schema so all events follow a clear format.
  • Ensure consistency. If an event wasn't processed, you can replay it thanks to Kafka's "At least once".

Final exercise

To reinforce what you've learned, design an event-driven architecture for an airline booking system. Identify key events (FlightBooked, PaymentProcessed, TicketIssued), their producers and subscribers. Describe service interactions and create an event flow diagram.

That's it! You've now hands-on practiced the basics of designing an event-driven architecture. Ahead — more EDA and async magic.

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION