Event Sourcing Pattern in Microservices (With Real-World Example)

🚀 Introduction: What is Event Sourcing in Microservices?

In traditional database systems, when an entity is updated, the old data is overwritten. However, in distributed microservices, this approach leads to:
Data inconsistency across multiple services
Lack of historical data tracking
Challenges in debugging and auditing

✅ Solution: The Event Sourcing Pattern

Instead of storing only the latest state, Event Sourcing stores all changes as a sequence of immutable events.

Each event represents a state change (e.g., OrderCreated, OrderUpdated, OrderCancelled).
✔ The current state is derived by replaying all past events.
✔ This allows full history tracking and easy recovery of previous states.

1️⃣ Real-World Use Case: How Banks Use Event Sourcing

Imagine you're managing bank transactions.
✔ When you deposit money, a record is updated.
✔ When you withdraw money, another record is updated.
✔ Over time, you lose historical records of each change.

Problem:

If a failure happens, there is no way to rebuild past transactions.

Solution: Event Sourcing

✅ Instead of storing just the current balance, store each transaction as an event.

📌 Example of Events:

1. DEPOSIT: +₹500  
2. WITHDRAW: -₹200  
3. TRANSFER: -₹100  

✅ The final balance is calculated by replaying all past events.

2️⃣ How Event Sourcing Works

📌 Instead of updating records, we append events:
✔ Each microservice generates events instead of modifying data.
✔ The events are stored in an Event Store (Kafka, EventStoreDB, or PostgreSQL).
✔ Services consume these events asynchronously to update their states.

🔄 Event Sourcing Workflow:

1️⃣ User places an orderOrderCreated event is generated.
2️⃣ Payment Service listens for OrderCreatedPaymentProcessed event is generated.
3️⃣ Inventory Service listens for PaymentProcessedInventoryUpdated event is generated.
4️⃣ Notification Service listens for OrderConfirmed → Sends confirmation email.

No direct service-to-service calls → Only event-driven updates.

3️⃣ Implementing Event Sourcing in Spring Boot Using Kafka

We will implement Event Sourcing using Spring Boot 3+ and Apache Kafka.

Step 1: Add Dependencies in pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
</dependency>

Kafka is used as the event store.
PostgreSQL is used for querying event data.

Step 2: Define an Order Event (Immutable Event Object)

public record OrderEvent(UUID orderId, String eventType, String eventData, LocalDateTime timestamp) {}

📌 This represents an event, not a database table.

Step 3: Implement Order Service (Publishing Events)

@Service
public class OrderService {
    private final KafkaTemplate<String, OrderEvent> kafkaTemplate;

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

    public void placeOrder(UUID orderId, String orderDetails) {
        OrderEvent orderEvent = new OrderEvent(orderId, "OrderCreated", orderDetails, LocalDateTime.now());
        kafkaTemplate.send("order-events", orderEvent);
    }
}

📌 Instead of saving in the database, we publish an event.

Step 4: Order Consumer (Handling Events from Kafka)

@Component
public class OrderEventConsumer {

    @KafkaListener(topics = "order-events", groupId = "order-group")
    public void consumeOrderEvent(OrderEvent orderEvent) {
        System.out.println("Received Event: " + orderEvent);
    }
}

Each microservice listens for events asynchronously.

Step 5: Order Controller (Triggering Events)

@RestController
@RequestMapping("/api/orders")
public class OrderController {
    private final OrderService orderService;

    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    @PostMapping
    public ResponseEntity<String> createOrder(@RequestParam String details) {
        UUID orderId = UUID.randomUUID();
        orderService.placeOrder(orderId, details);
        return ResponseEntity.ok("Order Created with ID: " + orderId);
    }
}

When an order is placed, an event is generated and published.

4️⃣ Querying Events Using PostgreSQL (Event Store as Database)

We can store all events in PostgreSQL to query the full history.

Step 1: Define an Event Entity

@Entity
@Table(name = "event_store")
public class EventEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private UUID orderId;
    private String eventType;
    private String eventData;
    private LocalDateTime timestamp;
}

Step 2: Implement an Event Repository

@Repository
public interface EventRepository extends JpaRepository<EventEntity, Long> {
    List<EventEntity> findByOrderId(UUID orderId);
}

This allows querying all past events for a specific order.

5️⃣ Benefits of Event Sourcing in Microservices

Full event history tracking (Auditability)
Easier debugging (Replay past events to analyze failures)
Improves system resilience (Event-driven architecture)
Better scalability (No direct service dependencies)
Enables CQRS (Command Query Responsibility Segregation)

6️⃣ Best Practices for Event Sourcing

Use an event store like Apache Kafka or EventStoreDB.
Ensure immutability (events should never be modified).
Implement an event versioning strategy (in case schema changes).
Use a separate query model (for optimized read performance).
Enable event replay to restore system state after failures.

🎯 Conclusion: Why Event Sourcing is Essential for Microservices?

By implementing Event Sourcing, you can:
✅ Maintain a full history of state changes.
✅ Improve fault tolerance and resilience.
✅ Ensure data consistency in distributed systems.

🚀 Have you implemented Event Sourcing in your microservices? Share your experience below!

🔗 Share this guide with developers to help them build scalable event-driven systems! 🚀

Comments

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare