Event-Driven Architecture
Key concepts
Event producers and consumers
Event bus patterns
Eventual consistency
Event sourcing
CQRS pattern
Overview
Event-driven architecture (EDA) is a design pattern where the flow of the program is determined by events—significant changes in state that components react to asynchronously. This pattern enables loosely coupled, scalable, and resilient systems by decoupling event producers from event consumers.
Understanding event-driven architecture is critical for the SAA-C03 exam because it underpins modern serverless and microservices designs. You must know when to use SNS vs SQS vs EventBridge, implement fan-out patterns for scalability, handle eventual consistency, and design for failure using dead-letter queues and retry mechanisms.
Event-Driven Benefits
Event-driven architecture decouples components so they can fail, scale, and evolve independently. Producers emit events without knowing who consumes them, and consumers process events without knowing who produced them. This loose coupling dramatically improves system resilience and scalability.
Exam scenarios often describe tightly coupled systems with reliability issues. The solution typically involves decoupling with SQS (point-to-point), SNS (fan-out), or EventBridge (content-based routing). Know when to use each service.
Key Concepts
Event-Driven Architecture Overview

Event-Driven Components
Event-driven architectures consist of three main components:
- Event Producers: Services that detect and emit events (e.g., S3, API Gateway, applications)
- Event Router/Bus: Service that receives, filters, and routes events (EventBridge, SNS)
- Event Consumers: Services that react to events (Lambda, SQS, Step Functions)
Events are immutable records of something that happened, not commands to do something.
Event Types
EVENT TYPES:
DOMAIN EVENTS (Business Events)
├── OrderPlaced, PaymentReceived, UserRegistered
├── Represent business-meaningful occurrences
├── Consumed by business logic
└── Example: {"event": "OrderPlaced", "orderId": "123", "amount": 99.99}
SYSTEM EVENTS (Infrastructure Events)
├── EC2 state changes, S3 object created, CloudWatch alarms
├── Emitted by AWS services automatically
├── Consumed for automation and monitoring
└── Example: {"source": "aws.ec2", "detail-type": "EC2 Instance State-change"}
INTEGRATION EVENTS (Cross-Service)
├── Events shared between microservices
├── Define service boundaries
├── Enable loose coupling
└── Example: {"source": "inventory-service", "detail-type": "StockUpdated"}AWS Event Services Comparison

Event Services Comparison
| Feature | Amazon SQS | Amazon SNS | Amazon EventBridge |
|---|---|---|---|
| Pattern | Point-to-point queue | Publish/Subscribe | Event bus with routing |
| Message Retention | Up to 14 days | No retention (immediate) | 24 hours replay |
| Ordering | FIFO available | FIFO available | Best effort |
| Filtering | No native filtering | Attribute-based filtering | Content-based rules |
| Targets | Single consumer polls | Multiple subscribers push | 20+ AWS service targets |
| Best For | Decoupling, buffering | Fan-out, notifications | Event routing, AWS integration |
Amazon SQS (Simple Queue Service)
Amazon SQS
SQS is a fully managed message queue for point-to-point asynchronous communication. Messages are stored until a consumer polls and processes them. Use SQS when you need to decouple components, buffer requests, or distribute work across workers.
STANDARD QUEUE:
├── Nearly unlimited throughput
├── At-least-once delivery (may have duplicates)
├── Best-effort ordering (may be out of order)
├── Use for: High throughput, duplicate-tolerant workloads
└── Price: Lower cost
FIFO QUEUE:
├── 300 TPS (3,000 with batching)
├── Exactly-once processing
├── Strict ordering within message groups
├── Use for: Order-sensitive processing, financial transactions
└── Price: Higher cost, requires .fifo suffix
KEY FEATURES:
├── Visibility Timeout: Prevents other consumers from processing
├── Dead Letter Queue (DLQ): Captures failed messages
├── Long Polling: Reduces empty responses, saves cost
├── Delay Queues: Postpone message delivery
└── Message Retention: 1 minute to 14 daysAmazon SNS (Simple Notification Service)
Amazon SNS
SNS is a fully managed pub/sub messaging service. Publishers send messages to topics, and all subscribers receive the message immediately. Use SNS when you need to fan-out messages to multiple consumers or send notifications.
SNS TOPIC TYPES:
STANDARD TOPIC:
├── High throughput
├── At-least-once delivery
├── Best-effort ordering
└── Use for: Notifications, fan-out
FIFO TOPIC:
├── Strict ordering
├── Exactly-once delivery
├── Works with SQS FIFO queues
└── Use for: Ordered processing pipelines
SUBSCRIBER TYPES:
├── Lambda functions
├── SQS queues
├── HTTP/HTTPS endpoints
├── Email/SMS
├── Mobile push
├── Kinesis Data Firehose
└── Other AWS accounts
MESSAGE FILTERING:
├── Filter by message attributes
├── Subscribers only receive matching messages
├── Reduces processing overhead
└── JSON filter policy on subscriptionAmazon EventBridge
Amazon EventBridge
EventBridge is a serverless event bus that connects applications using events. It provides sophisticated content-based routing, transformation, and native integration with 100+ AWS services. Use EventBridge as default for new event-driven architectures.
EVENTBRIDGE ARCHITECTURE:
EVENT BUS:
├── Default Bus: Receives AWS service events
├── Custom Bus: For your application events
├── Partner Bus: Third-party SaaS events
└── Cross-account buses supported
RULES:
├── Match events using patterns
├── Route to one or more targets
├── Transform events before delivery
├── Up to 300 rules per bus
└── 5 targets per rule
EVENT PATTERN (Example):
{
"source": ["aws.ec2"],
"detail-type": ["EC2 Instance State-change Notification"],
"detail": {
"state": ["stopped", "terminated"]
}
}
TARGETS:
├── Lambda, Step Functions
├── SQS, SNS, Kinesis
├── ECS tasks, CodePipeline
├── API Gateway, API destinations
├── Other event buses
└── 20+ supported targetsCommon Event-Driven Patterns
Fan-Out Pattern

Fan-Out Pattern
The fan-out pattern uses SNS to distribute a single message to multiple SQS queues simultaneously. Each queue represents a different processing path, enabling parallel, independent processing of the same event.
FAN-OUT PATTERN:
┌─── SQS Queue 1 ─── Lambda (Analytics)
│
SNS Topic ──────────┼─── SQS Queue 2 ─── Lambda (Notification)
│
└─── SQS Queue 3 ─── Lambda (Archival)
USE CASES:
├── Process same event for multiple purposes
├── Different processing speeds per consumer
├── Fault isolation (one queue failure doesn't affect others)
├── Different scaling requirements
└── A/B testing with parallel paths
BENEFITS:
├── Decoupled consumers
├── Independent scaling
├── Fault isolation
├── Message durability (SQS retention)
└── Asynchronous processingEvent Sourcing Pattern
Event Sourcing
Event sourcing stores all changes to application state as a sequence of events. Instead of storing current state, you store every event that led to that state. Events can be replayed to reconstruct state at any point in time.
EVENT SOURCING ARCHITECTURE:
WRITE PATH:
Command → Validate → Store Event → Publish Event
│ │ │
│ ▼ ▼
│ DynamoDB EventBridge
│ (Event Store) │
│ ▼
└─────────────────────── Update Read Model
EVENT STORE (DynamoDB):
┌──────────────────────────────────────────────────────┐
│ PK: order-123 SK: event-001 Data: OrderCreated │
│ PK: order-123 SK: event-002 Data: ItemAdded │
│ PK: order-123 SK: event-003 Data: PaymentReceived│
│ PK: order-123 SK: event-004 Data: OrderShipped │
└──────────────────────────────────────────────────────┘
BENEFITS:
├── Complete audit trail
├── Temporal queries (state at any time)
├── Event replay for debugging
├── Supports CQRS pattern
└── Natural fit for event-driven systems
CHALLENGES:
├── Eventual consistency
├── Event schema evolution
├── Storage growth over time
└── Complexity in queryingCQRS Pattern
CQRS (Command Query Responsibility Segregation)
CQRS separates read and write operations into different models. Commands (writes) go to one data store optimized for writes, while queries (reads) go to another optimized for reads. The read model is updated asynchronously via events.
CQRS ARCHITECTURE:
COMMANDS QUERIES
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ API GW │ │ API GW │
│ (Write) │ │ (Read) │
└────┬─────┘ └────┬─────┘
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ Lambda │ │ Lambda │
│ (Command)│ │ (Query) │
└────┬─────┘ └────┬─────┘
│ │
▼ ▼
┌──────────┐ Events ┌──────────┐
│ DynamoDB │ ──────────────► │ Aurora │
│ (Write) │ EventBridge │ (Read) │
└──────────┘ └──────────┘
WHEN TO USE CQRS:
├── Read and write loads differ significantly
├── Complex domain with different read/write models
├── Need to scale reads and writes independently
├── Acceptable eventual consistency for reads
└── Different teams work on read vs write
WHEN NOT TO USE:
├── Simple CRUD applications
├── Strong consistency required everywhere
├── Small scale, low complexity
└── Single team, rapid iterationEventual Consistency
Eventual Consistency
In event-driven systems, data changes propagate asynchronously, leading to eventual consistency. Given enough time, all nodes will have the same data, but there may be temporary inconsistencies. Design your application to handle this gracefully.
Consistency Models
| Model | Guarantee | Latency | Use Case |
|---|---|---|---|
| Strong Consistency | Read always returns latest write | Higher | Financial transactions, inventory |
| Eventual Consistency | Read may return stale data temporarily | Lower | Analytics, caching, read replicas |
| Read-Your-Writes | User sees their own writes immediately | Medium | User profiles, shopping carts |
STRATEGIES FOR EVENTUAL CONSISTENCY:
1. OPTIMISTIC UI
├── Update UI immediately (assume success)
├── Reconcile when event confirms
└── Handle conflicts gracefully
2. IDEMPOTENT CONSUMERS
├── Processing same event twice has same result
├── Use event ID for deduplication
└── Critical for at-least-once delivery
3. VERSION TRACKING
├── Include version in events and state
├── Reject stale updates
└── Implement optimistic locking
4. COMPENSATION EVENTS
├── When things go wrong, emit compensating event
├── OrderCancelled reverses OrderPlaced
└── Saga pattern for distributed transactions
5. READ-YOUR-WRITES
├── Route user's reads to same replica they wrote to
├── Or cache recent writes client-side
└── Provides consistency illusionDead Letter Queues and Error Handling
Dead Letter Queues (DLQ)
A Dead Letter Queue captures messages that cannot be processed successfully after a specified number of retries. DLQs prevent poison messages from blocking the queue and provide a mechanism to analyze and reprocess failed messages.
DLQ ARCHITECTURE:
Source Queue ──► Consumer ──► Success
│
├── Retry 1 ──► Fail
├── Retry 2 ──► Fail
├── Retry 3 ──► Fail
│
▼
Dead Letter Queue ──► Analysis/Reprocessing
SQS DLQ CONFIGURATION:
{
"RedrivePolicy": {
"deadLetterTargetArn": "arn:aws:sqs:region:account:my-dlq",
"maxReceiveCount": 3
}
}
LAMBDA EVENT SOURCE DLQ:
├── Configure on Lambda event source mapping
├── Failed events after retries go to DLQ
├── Works with SQS, Kinesis, DynamoDB Streams
└── Preserves event for reprocessing
EVENTBRIDGE DLQ:
├── Configure on rule target
├── Captures events that fail delivery
├── Includes error information
└── Enables retry and analysis
BEST PRACTICES:
├── Always configure DLQs for production
├── Set up CloudWatch alarms on DLQ depth
├── Include correlation IDs for tracing
├── Implement automated reprocessing where safe
└── Manual review for unknown failuresBest Practices
Design Principles
- Design for Failure: Assume components will fail; use DLQs, retries, and circuit breakers
- Make Consumers Idempotent: Same event processed twice should produce same result
- Use EventBridge as Default: Prefer EventBridge for new architectures over SNS
- Include Metadata: Add correlation IDs, timestamps, and version to events
- Schema Evolution: Plan for backward-compatible event schema changes
- Monitor Everything: Track event throughput, latency, DLQ depth, and consumer lag
- Right-Size Batching: Balance throughput and latency with batch sizes
Service Selection Guide
USE SQS WHEN:
├── Need message buffering/retention
├── Want to control processing rate
├── Need exactly-once with FIFO
├── Decoupling producer from consumer speed
├── Work distribution to multiple workers
└── Handling traffic spikes gracefully
USE SNS WHEN:
├── Need fan-out to multiple consumers
├── Push-based delivery required
├── Sending notifications (email, SMS, mobile)
├── Simple pub/sub without complex routing
└── A2A (application-to-application) messaging
USE EVENTBRIDGE WHEN:
├── Need content-based event routing
├── Integrating with AWS service events
├── Building event-driven microservices
├── Want event transformation/enrichment
├── Cross-account or cross-region events
├── SaaS integration (partner events)
└── Default choice for new architecturesCommon Exam Scenarios
Exam Scenarios
| Scenario | Solution | Why |
|---|---|---|
| Decouple web tier from processing tier | SQS queue between tiers | Buffering, independent scaling |
| Single event to multiple systems | SNS fan-out to SQS queues | Parallel processing, fault isolation |
| Route AWS service events to Lambda | EventBridge rule | Native integration, content filtering |
| Process events in strict order | SQS FIFO queue | Exactly-once, ordering guarantee |
| Handle burst traffic from API | API Gateway → SQS → Lambda | Queue absorbs bursts |
| Failed messages need investigation | Configure DLQ | Captures failures for analysis |
| Scale workers based on queue depth | SQS + Auto Scaling on ApproximateNumberOfMessages | Dynamic scaling to demand |
| Different actions for different event types | EventBridge rules with patterns | Content-based routing |
Common Pitfalls
Pitfall 1: Not Configuring DLQs
Mistake: Deploying queues and event rules without dead letter queues.
Why it fails: Poison messages block processing; failed events are lost forever.
Correct Approach: Always configure DLQs; set up alarms on DLQ message count.
Pitfall 2: Non-Idempotent Consumers
Mistake: Consumers that produce different results when processing the same event twice.
Why it fails: SQS Standard and SNS deliver at-least-once; duplicates happen.
Correct Approach: Design idempotent consumers; use event ID for deduplication.
Pitfall 3: Synchronous Event Processing
Mistake: Having event consumers call other services synchronously, waiting for responses.
Why it fails: Creates tight coupling; defeats purpose of event-driven design.
Correct Approach: Consumers should process independently; emit new events if needed.
Pitfall 4: Ignoring Eventual Consistency
Mistake: Designing UI and APIs assuming immediate consistency after events.
Why it fails: Read models may not reflect recent writes; causes user confusion.
Correct Approach: Implement read-your-writes, optimistic UI, or explicit loading states.
Pitfall 5: Using SQS for Fan-Out
Mistake: Multiple consumers polling the same SQS queue expecting all to receive every message.
Why it fails: SQS is point-to-point; once a message is read, others don't see it.
Correct Approach: Use SNS → SQS fan-out; each consumer gets its own queue.
Related Services
Quick Reference
Message Service Limits
Service Limits
| Service | Message Size | Retention | Throughput |
|---|---|---|---|
| SQS Standard | 256 KB | 14 days max | Nearly unlimited |
| SQS FIFO | 256 KB | 14 days max | 300 TPS (3K batched) |
| SNS | 256 KB | No retention | Nearly unlimited |
| EventBridge | 256 KB | 24h replay | 10K events/sec (soft) |
Event Pattern Syntax
// Match EC2 instance state changes
{
"source": ["aws.ec2"],
"detail-type": ["EC2 Instance State-change Notification"],
"detail": {
"state": ["running", "stopped"]
}
}
// Match S3 object creation in specific bucket
{
"source": ["aws.s3"],
"detail-type": ["Object Created"],
"detail": {
"bucket": {
"name": ["my-bucket"]
}
}
}
// Match custom application events with prefix
{
"source": ["myapp.orders"],
"detail-type": ["Order Placed"],
"detail": {
"amount": [{"numeric": [">=", 100]}],
"region": [{"prefix": "us-"}]
}
}Test Your Knowledge
A company needs to process the same order event in three different systems: inventory, billing, and shipping. Each system has different processing speeds and should not block the others. What architecture should be used?
An application occasionally receives duplicate messages from an SQS Standard queue. The processing involves inserting records into a database. How should the application handle this?
A serverless application uses EventBridge to route events to Lambda functions. Some events are failing to process and being lost. What should be implemented?
Which service should be used as the default choice when building a new event-driven architecture that routes events based on content to different AWS services?