7.7 KiB
Event-Driven Architecture Template
Use this template when designing event-driven systems with asynchronous communication.
Event Schema Definition
Event: [EventName]
{
"eventId": "uuid",
"eventType": "[EventName]",
"eventVersion": "1.0",
"timestamp": "ISO8601",
"source": "[ServiceName]",
"correlationId": "uuid",
"payload": {
// Event-specific data
},
"metadata": {
"userId": "string",
"traceId": "string"
}
}
Trigger: [When is this event published?] Consumers: [Which services consume this event?] Retention: [How long to keep in event store?]
Event Catalog
| Event Name | Version | Producer | Consumers | Schema Registry |
|---|---|---|---|---|
| OrderPlaced | 1.0 | OrderService | PaymentService, InventoryService | schema-registry/order-placed-v1.json |
| PaymentProcessed | 1.0 | PaymentService | OrderService, NotificationService | schema-registry/payment-processed-v1.json |
Event Broker Configuration
- Platform: [Kafka / RabbitMQ / AWS EventBridge / Google Pub/Sub]
- Topics/Queues:
orders.placed- Order creation eventspayments.processed- Payment completion eventsinventory.updated- Stock level changes
- Partitioning strategy: [By customer ID / By order ID / Round-robin]
- Replication factor: [3 for production]
- Retention period: [7 days for event replay]
Producer Configuration
Service: [ProducerServiceName]
Events Published:
- [EventName]: Published when [business event occurs]
- Partition key: [customer_id / entity_id]
- Ordering guarantee: [Yes/No]
- Retry policy: [3 retries with exponential backoff]
Reliability Patterns:
- Outbox pattern: Write to database + outbox table atomically
- At-least-once delivery: Idempotent event production
- Schema validation: Validate against schema registry before publishing
- Failure handling: Store failed events in dead letter queue
Code Example:
async def publish_event(event: OrderPlaced):
# Transactional outbox pattern
async with db.transaction():
await db.orders.create(event.order)
await db.outbox.insert({
"event_id": event.id,
"event_type": "OrderPlaced",
"payload": event.to_json(),
"status": "pending"
})
# Asynchronous event publishing (handled by outbox processor)
await event_broker.publish(
topic="orders.placed",
key=event.customer_id,
value=event.to_json(),
headers={"trace_id": trace_id}
)
Consumer Configuration
Service: [ConsumerServiceName]
Events Consumed:
- [EventName]: From [ProducerService]
- Consumer group:
[service-name]-[event-name] - Concurrency: [N parallel workers]
- Max retries: [5 with exponential backoff]
- Dead letter queue:
[event-name].dlq
- Consumer group:
Processing Patterns:
- Idempotency: Check event ID before processing
- Ordering: Process events in order within partition
- Error handling: Retry transient errors, DLQ for permanent failures
- Acknowledgment: Acknowledge only after successful processing
Code Example:
@consumer(topic="orders.placed", group="payment-service-orders")
async def process_order_placed(event: OrderPlaced):
# Idempotency check
if await db.processed_events.exists(event.id):
logger.info(f"Event {event.id} already processed")
return
try:
# Business logic
payment = await payment_service.process_payment(event.order)
# Mark as processed
await db.processed_events.insert(event.id)
# Publish downstream event
await publish_event(PaymentProcessed(payment))
except RetryableError as e:
logger.warning(f"Retrying event {event.id}: {e}")
raise # Will be retried
except PermanentError as e:
logger.error(f"Sending event {event.id} to DLQ: {e}")
await dlq.send(event, error=str(e))
Event Sourcing
Use when: Need complete audit trail and event replay capabilities.
Aggregate: [AggregateName]
Command Handlers:
- CreateOrder: Validates and produces OrderCreated event
- UpdateOrderStatus: Produces OrderStatusUpdated event
Event Store:
- Storage: [PostgreSQL event_store table / EventStoreDB / Kafka topic]
- Schema:
CREATE TABLE events ( event_id UUID PRIMARY KEY, aggregate_id UUID NOT NULL, aggregate_type VARCHAR(100), event_type VARCHAR(100), event_data JSONB, event_version INT, created_at TIMESTAMP, INDEX(aggregate_id, event_version) );
Snapshot Strategy:
- Create snapshot every [100] events
- Store in separate
snapshotstable - Load latest snapshot + subsequent events for aggregate rebuild
Saga Pattern (Distributed Transactions)
Saga: [SagaName]
Orchestration Approach: [Choreography / Orchestrator]
Steps:
- OrderService → Publish
OrderPlaced - PaymentService → Process payment → Publish
PaymentProcessedorPaymentFailed - InventoryService → Reserve stock → Publish
InventoryReservedorInventoryUnavailable - ShippingService → Schedule shipment → Publish
ShipmentScheduled
Compensation (Rollback):
- If
PaymentFailed→ PublishOrderCancelled - If
InventoryUnavailable→ PublishPaymentRefunded→OrderCancelled
State Machine:
[Order Created] → [Payment Processing] → [Inventory Reserved] → [Shipment Scheduled] → [Order Completed]
↓ ↓ ↓
[Order Cancelled] ← [Payment Failed] ← [Inventory Unavailable]
Schema Evolution
Versioning Strategy: [Backward compatible / Forward compatible / Full compatibility]
Schema Registry: [Confluent Schema Registry / AWS Glue Schema Registry]
Version Migration:
- v1 → v2 Changes:
- Added optional field:
customer_email - Deprecated field:
customer_address(useshipping_addressinstead)
- Added optional field:
- Consumer compatibility: Old consumers can read v2 events (ignore new fields)
- Producer compatibility: New producers can emit v1 events if needed
Monitoring & Observability
Metrics:
- Event publish rate and latency
- Consumer lag (events behind current offset)
- Processing errors and retry count
- Dead letter queue size
Alerts:
- Consumer lag > [1000 events]
- Error rate > [5%]
- DLQ messages > [100]
- Event processing latency p99 > [500ms]
Distributed Tracing:
- Propagate trace IDs across events
- Track event flow: Producer → Broker → Consumer → Downstream events
Testing
Unit Tests:
- Event schema validation
- Idempotency logic
- Compensation logic (saga rollback)
Integration Tests:
- End-to-end event flow
- Consumer error handling and retries
- Dead letter queue behavior
Chaos Testing:
- Simulate broker downtime
- Duplicate event delivery
- Out-of-order event delivery
- Consumer crash mid-processing
Security
- Encryption: TLS for data in transit, encryption at rest for event store
- Authorization: ACLs for topic access (producers/consumers)
- Audit: Log all event publications and consumptions
- PII handling: Encrypt sensitive fields in event payload
Cost Optimization
- Retention policy: Delete events older than [X days]
- Compaction: Use log compaction for entity snapshots
- Resource allocation: Right-size broker and consumer resources
- Batch processing: Batch consume events to reduce overhead
Disaster Recovery
- Event replay: Re-process events from timestamp/offset
- Backup: Regular snapshots of event store
- Cross-region replication: Mirror events to DR region
- RTO/RPO: Recovery time objective [X hours], Recovery point objective [X minutes]