ADR-0002: Use NATS JetStream for Event Bus
- Status: Accepted
- Date: 2025-12-29
- Deciders: @anshpansuriya14
- Supersedes: N/A
- Superseded by: N/A
Context
Framework M needs an event-driven architecture for:
- Domain events (
doc.created,doc.updated,doc.deleted) - Webhook triggers
- Audit logging
- Real-time notifications
- Decoupled service communication
Forces at play:
- Reliability: Events must not be lost
- Replay Capability: New subscribers should access historical events
- Pattern Matching: Subscribe to
doc.*ortodo.created - Consistency: Same infrastructure for jobs and events
- Performance: High throughput, low latency
Decision
We will use NATS JetStream via
nats-pyfor the event bus.
from nats.aio.client import Client
async def publish_event(nc: Client, topic: str, event: BaseEvent):
await nc.publish(topic, event.model_dump_json().encode())
async def subscribe_events(nc: Client, pattern: str, handler):
await nc.subscribe(pattern, cb=handler)
Consequences
Positive
- Shared Infrastructure: Same NATS cluster for jobs (ADR-0001) and events
- JetStream Durability: Messages persisted, consumers can replay from any point
- Wildcard Subscriptions:
doc.*,todo.>patterns for flexible routing - At-Least-Once: Acknowledgment-based delivery prevents message loss
- Cross-Language: NATS has clients for Go, Rust, JS (future microservices)
Negative
- Complexity: JetStream streams require configuration (retention, limits)
- Ordering: Partitioned ordering (by key) not global order
- Learning Curve: Different model than Redis Pub/Sub
Neutral
- Messages use CloudEvents format for interoperability
- Consumer groups supported via queue subscriptions
Alternatives Considered
| Option | Pros | Cons |
|---|---|---|
| Chosen: NATS JetStream | Durable, replay, shared with jobs | Learning curve |
| Redis Pub/Sub | Simple, fast | No persistence, no replay |
| Redis Streams | Persistent, consumer groups | No pattern matching, Redis-only |
| Kafka | Enterprise-grade, proven | Heavy, operational complexity |
| RabbitMQ | Mature, flexible routing | Separate system from jobs |