Overview
The User Service communicates with other services via Amazon EventBridge, a serverless event bus. This provides loose coupling, enabling services to react to user lifecycle events without direct dependencies.Why EventBridge?
| Requirement | EventBridge | SQS |
|---|---|---|
| One event → multiple consumers | Native fan-out | Requires SNS+SQS or multiple queues |
| Event filtering | Rules with pattern matching | Limited (message attributes) |
| Schema management | Schema Registry | Manual |
| Audit trail | Archive and replay | Manual implementation |
| Cross-account | Native support | Requires configuration |
SQS is ideal for point-to-point messaging or work queues. EventBridge is better for event-driven architectures where multiple services react to the same event.
Events Published
User Events
| Event Type | Trigger | Payload |
|---|---|---|
user.created | Post-confirmation trigger | userId, email, timestamp |
user.updated | Profile update | userId, changedFields, timestamp |
user.deleted | Account deletion | userId, timestamp |
user.suspended | Admin action | userId, reason, timestamp |
user.reactivated | Admin action | userId, timestamp |
Email Events
| Event Type | Trigger | Payload |
|---|---|---|
email.added | New email added | userId, emailId, email |
email.verified | Verification confirmed | userId, emailId, email |
email.removed | Email deleted | userId, emailId, email |
email.primary.changed | Primary email changed | userId, oldEmail, newEmail |
Event Schema
All events follow a consistent envelope:Schema Fields
| Field | Type | Description |
|---|---|---|
version | string | Schema version for evolution |
source | string | Publishing service identifier |
detail-type | string | Event type (domain.action format) |
time | ISO8601 | Event timestamp |
detail | object | Event-specific payload |
detail.metadata.correlationId | string | Request tracing ID |
Event Consumers
Who Subscribes to What?
| Service | Events | Purpose |
|---|---|---|
| Notification | user.created, email.added, email.verified, email.primary.changed | Send welcome emails, verification codes, confirmations |
| Booking | user.deleted, user.suspended | Cancel pending bookings, block new bookings |
| Billing | user.deleted, email.primary.changed | Final invoice, update billing contact |
| Analytics | user.*, email.* | Usage tracking, conversion funnels |
| Search Index | user.updated, user.deleted | Keep search index in sync |
EventBridge Rules
Events Consumed
The User Service also consumes events from other services:| Event | Source | Action |
|---|---|---|
cognito.user.confirmed | Cognito (via trigger) | Create DynamoDB user record |
billing.subscription.changed | Billing Service | Update user tier/status |
admin.user.suspend | Admin Service | Set user status to suspended |
Hard Parts
Event Ordering
Problem: Events may arrive out of order.user.updated might arrive before user.created.
Solution:
- Timestamps: Every event includes
time. Consumers can discard stale events. - Idempotent handlers: Operations should be safe to retry or reorder.
- Last-write-wins: For non-critical data, accept the latest timestamp.
Eventual Consistency
Problem: Afteruser.deleted, other services may still show the user briefly.
Solution:
- Accept it: Most use cases tolerate seconds of delay.
- Critical path queries: For operations that cannot tolerate stale data, query the source service directly.
Failed Event Processing
Problem: Consumer fails to process an event (bug, downstream outage). Solution: Dead Letter Queue (DLQ) with alerting and replay capability. DLQ Configuration:- Max retries: 3 (with exponential backoff)
- DLQ retention: 14 days
- Alarm on DLQ depth > 0
Guaranteed Delivery
Problem: Lambda publishes to DynamoDB but EventBridge call fails. Event is lost. Solution: Transactional Outbox Pattern1
Write to Outbox
In the same DynamoDB transaction, write the event to an outbox table
2
Async Publisher
Separate Lambda polls outbox (or uses DynamoDB Streams) and publishes to EventBridge
3
Delete from Outbox
After successful publish, delete from outbox
Schema Evolution
Adding Fields
New fields can be added without breaking consumers:Changing Fields
For breaking changes:- Increment version
- Publish both versions during transition
- Consumers upgrade to new version
- Stop publishing old version