The talk is about how we at Luno design our micro services and distributed application logic so that it is robust to failures and easy to maintain. We do this by coupling mutable state with immutable events.
a mutable table. • Use state machines to control updates. • Couple with an immutable events table. • Expose events as gRPC streams. • Build application logic as idempotent consumers. • Explicitly introduce failures in application logic.
understand for humans. • Mimics the real world. • Querying the current state is trivial. type Send struct { ID int64 UserID int64 Amount int64 Address string Status Status // PENDING, COMPLETED, FAILED TxID string // Non-zero if COMPLETED Error string // Non-zero if FAILED }
-+ v | CREATED --> PENDING --> FAILED | +-------> COMPLETED State machines • Explicit control of state life cycle. • Defined as rooted directed graph. • Easy for humans to understand. • Decompose complexity in discrete steps. • Transitions are events.
Fowler: event sourcing vs event notification. • Persistence guarantees are critical. • SQL transactions provide exactly once event persistence. type Event struct { ID int64 Timestamp time.Time ForeignID int64 // Send.ID Type Type // Send.Status }
sequentially. • Consumers keep a cursor of their position. • Streams are not queues. • Retry on errors or ignore and continue. • Delivery guarantees are critical. • gRPC supports streaming connections.
events send_events Create send Get send Stream events DB Sender Service Layers State Machine Business Logic gRPC API Create hander Sender consumer Get hander Events Insert Stream Reflex Shift PENDING FAILED COMPLETED