PubSub: The Event-Driven Foundation
How we built a publish-subscribe system that became the nervous system of our entire platform.
By 2012, we had storage (datastore) and state (KV). But our services were still talking to each other through HTTP calls - brittle, synchronous, and prone to cascading failures. We needed a better way.
The Problem with Request-Response
Traditional architectures look like this:
User → API → Service A → Service B → Database
↓
Service C
If Service B is slow, everything is slow. If Service C fails, do you retry? Roll back? The complexity explodes exponentially with each new service.
Event-Driven Architecture
We flipped the model:
User → API → Event Bus
↓
┌─────────┼─────────┐
↓ ↓ ↓
Service A Service B Service C
Services publish events. Other services subscribe to events they care about. No service knows who's listening. No service waits for others.
PubSub Design Principles
At-Least-Once Delivery: Messages are never lost. Duplicates are possible (design for idempotency).
Ordered Within Partition: Events for the same entity arrive in order.
Backpressure: Slow consumers don't overwhelm the system.
Dead Letter Queues: Failed messages go somewhere for debugging.
# Publishing is fire-and-forget
pubsub.publish("orders", {
"event": "order.created",
"order_id": "12345",
"user_id": "user_789",
"items": [...]
})
# Subscribers handle asynchronously
@pubsub.subscribe("orders", "inventory-service")
def handle_order(event):
if event["event"] == "order.created":
reserve_inventory(event["items"])
Why This Was Revolutionary
In 2012, Kafka was only a year old and barely production-ready. RabbitMQ existed but was complex to operate. AWS SNS/SQS were primitive.
We built PubSub with:
- Persistent storage: Messages survived restarts
- Consumer groups: Multiple instances of a service shared load
- Replay capability: Debug by replaying historical events
- Schema registry: Events had versions, migrations were possible
The Ripple Effect
Event-driven architecture changed how we built everything:
- Analytics: Every event flows to our data warehouse automatically
- Audit logging: Complete history of every action
- Notifications: Email, push, SMS triggered by events
- Search indexing: Elasticsearch updated via events
- Billing: Usage tracked by events, invoices generated asynchronously
The Philosophy
The core insight: services should tell the world what happened, not instruct other services what to do.
order.created is better than reserve_inventory + send_confirmation + update_analytics. The first describes reality. The second couples systems together.
This philosophy - publish facts, not commands - became central to Hanzo's architecture and influenced the Model Context Protocol (MCP) we built years later.
This post is part of our retrospective series exploring the technical foundations of Hanzo.
Read more
Webhooks: Real-Time Event Delivery
Announcing Hanzo Webhooks: reliable, secure, real-time event delivery for your integrations.
Half a Million RPS on a GB10: The Network Was the Bottleneck, Not the Box
We set out to see how fast our cloud data plane could go on an NVIDIA GB10. The answer taught us more about NIC receive queues than about our own code — and it more than doubled our throughput on the same wire.
BitDelta: Serving 14 Zen Models from One GPU Cluster
How BitDelta's 1-bit delta compression lets us serve 14 Zen model variants from shared GPU infrastructure — the math, the architecture, and the tradeoffs.