Implementing Event-Driven Architecture
1. Understanding Event Sourcing Pattern
| Property | Detail |
|---|---|
| State derivation | State = fold(events) |
| Append-only | Events immutable |
| Audit log | Built-in history |
| Time travel | Replay to any point |
| Examples | EventStoreDB, Axon, Marten |
2. Implementing Event Store Design
| Element | Detail |
|---|---|
| Stream | Per-aggregate event sequence |
| Event id | UUID, deduplication anchor |
| Sequence number | Per-stream monotonic |
| Global position | Total order across streams |
| Optimistic concurrency | Append with expected version |
3. Implementing Event Replay and Projection
Example: Account projection
public class AccountProjection {
private long balance = 0;
public void apply(DepositedEvent e) { balance += e.amount; }
public void apply(WithdrawnEvent e) { balance -= e.amount; }
public static AccountProjection rebuild(List<Event> events) {
AccountProjection p = new AccountProjection();
for (Event e : events) p.dispatch(e);
return p;
}
}
| Optimization | Detail |
|---|---|
| Snapshots | Fold every N events; replay tail only |
| Materialized views | Persist projections for queries |
| Catch-up subscriptions | Subscribe from last position |
4. Understanding CQRS Pattern
| Side | Model |
|---|---|
| Command | Validates, mutates, emits events |
| Query | Read-optimized projections |
| Sync | Events propagate from write → read |
| Pros | Independent scaling and schema |
| Cons | Eventual consistency between sides |
5. Implementing Event Bus
| Implementation | Detail |
|---|---|
| In-process | Spring ApplicationEventPublisher, MediatR |
| Distributed | Kafka, RabbitMQ, NATS, EventBridge |
| Schema registry | Confluent, Apicurio for evolution |
| CloudEvents spec | Standardized envelope |
6. Implementing Event Schema Evolution
| Strategy | Detail |
|---|---|
| Additive only | New optional fields safe |
| Versioned event types | OrderCreatedV2 |
| Upcaster | Transforms old events on read |
| Compatibility mode | Schema registry enforces BACKWARD |
7. Handling Event Ordering and Causality
| Guarantee | Mechanism |
|---|---|
| Per-aggregate order | Partition by aggregate id |
| Causal across aggregates | Vector clock / causal id |
| Total order | Single partition (limited throughput) |
| Out-of-order tolerance | Watermarks, late event handling |
8. Implementing Event Deduplication
| Method | Detail |
|---|---|
| Event id set | Track processed ids in DB / Redis |
| Idempotent handlers | Apply naturally idempotent |
| Producer dedup id | Kafka enable.idempotence=true |
| Window-based dedup | Fixed time window (Flink) |
9. Understanding Domain Events vs Integration Events
10. Implementing Outbox Pattern
Transactional Outbox
- In single DB transaction: write entity + insert into
outboxtable - Background relay polls outbox or reads CDC log (Debezium)
- Publish to broker (Kafka, RabbitMQ)
- Mark outbox row as published / delete
- Consumers dedup using event id
Note: Outbox guarantees no event lost when DB commits, eliminating dual-write inconsistency.