Event-Driven Architecture
Pub/sub patterns, queue topology, and idempotency guarantees.
Event topology
Producer (API) → Redis Queue → Consumer (Worker) → Side effects
↓
Dead letter queue (failed after max retries)Event envelope
Every event follows a standard shape:
{
"id": "evt_01HZ...",
"type": "user.created",
"timestamp": "2026-05-24T18:00:00Z",
"source": "backend-api",
"data": {
"userId": "usr_123",
"email": "user@company.com"
}
}Idempotency
Consumers must handle duplicate delivery:
async function handleUserCreated(event: Event) {
const existing = await db.processedEvent.findUnique({
where: { eventId: event.id },
});
if (existing) return; // Already processed
await db.$transaction([
db.processedEvent.create({ data: { eventId: event.id } }),
// ... side effects
]);
}Naming conventions
| Pattern | Example |
|---|---|
| Entity action | user.created, order.paid |
| System event | deployment.completed |
| Integration | stripe.payment_intent.succeeded |