Skip to content

SNS, SQS, and EventBridge

First PublishedByAtif Alam

Messaging services decouple producers from consumers — instead of Service A calling Service B directly, it sends a message that Service B picks up later. This makes systems more resilient, scalable, and easier to evolve.

ServiceModelPatternUse Case
SQSQueuePoint-to-pointWorker processing, task queues, buffering
SNSPub/SubFan-out (one-to-many)Notifications, broadcasting events to multiple consumers
EventBridgeEvent busEvent routing with rulesEvent-driven architectures, cross-service integration, SaaS events
Producer ──► SQS Queue ──► Single Consumer (pull)
Producer ──► SNS Topic ──► Consumer A
──► Consumer B (fan-out)
──► Consumer C
Producer ──► EventBridge ──► Rule 1 ──► Lambda
──► Rule 2 ──► SQS Queue (content-based routing)
──► Rule 3 ──► Step Functions

SQS is a fully managed message queue. Producers send messages; consumers poll and process them.

Standard QueueFIFO Queue
OrderingBest-effort (mostly ordered)Guaranteed first-in-first-out
DeliveryAt-least-once (possible duplicates)Exactly-once processing
ThroughputNearly unlimited300 msg/s (3,000 with batching)
Use caseHigh-throughput work where order doesn’t matterFinancial transactions, order processing
Producer ──send──► [ msg3 msg2 msg1 ] ──receive──► Consumer
SQS Queue │
process msg1
delete msg1
  1. Producer sends a message to the queue.
  2. Consumer receives (polls) a message — the message becomes invisible to other consumers.
  3. Consumer processes the message.
  4. Consumer deletes the message from the queue.
  5. If the consumer fails (doesn’t delete within the visibility timeout), the message reappears for retry.
SettingWhat It DoesDefault
Visibility timeoutHow long a received message is hidden from other consumers30 seconds
Message retentionHow long unprocessed messages are kept4 days (max 14)
Receive wait timeLong polling wait (0 = short polling, 1–20s = long polling)0 (short)
Delay secondsDelay before a new message becomes visible0
Max message sizeMaximum message body256 KB

Always use long polling (ReceiveWaitTimeSeconds: 20) — it reduces empty responses and API costs.

A DLQ catches messages that fail processing repeatedly:

Main Queue ──► Consumer fails 3 times ──► Dead-Letter Queue
Investigate and fix
Terminal window
# Create a DLQ
aws sqs create-queue --queue-name orders-dlq
# Set DLQ on the main queue (after 3 failed receives)
aws sqs set-queue-attributes --queue-url https://sqs.../orders \
--attributes '{
"RedrivePolicy": "{\"deadLetterTargetArn\":\"arn:aws:sqs:us-east-1:123456789012:orders-dlq\",\"maxReceiveCount\":\"3\"}"
}'

Lambda can poll SQS automatically — no need to write polling code:

Terminal window
aws lambda create-event-source-mapping \
--function-name process-orders \
--event-source-arn arn:aws:sqs:us-east-1:123456789012:orders \
--batch-size 10

Lambda scales up consumers based on queue depth.

import boto3, json
sqs = boto3.client('sqs')
queue_url = 'https://sqs.us-east-1.amazonaws.com/123456789012/orders'
# Send
sqs.send_message(
QueueUrl=queue_url,
MessageBody=json.dumps({'order_id': 123, 'amount': 49.99}),
MessageAttributes={
'priority': {'DataType': 'String', 'StringValue': 'high'}
}
)
# Receive and process
response = sqs.receive_message(
QueueUrl=queue_url,
MaxNumberOfMessages=10,
WaitTimeSeconds=20 # long polling
)
for msg in response.get('Messages', []):
body = json.loads(msg['Body'])
process_order(body)
sqs.delete_message(QueueUrl=queue_url, ReceiptHandle=msg['ReceiptHandle'])

SNS is a pub/sub service — a producer publishes a message to a topic, and all subscribers receive it.

Publisher ──publish──► SNS Topic ──► SQS Queue (subscriber)
──► Lambda (subscriber)
──► Email (subscriber)
──► HTTP endpoint (subscriber)
TypeUse Case
SQSFan-out to queues for async processing
LambdaTrigger serverless functions
HTTP/HTTPSWebhook to external services
EmailNotifications to humans
SMSText message alerts
Kinesis FirehoseStream events to S3, Redshift, etc.

The most common pattern — one event triggers multiple independent processors:

Order placed ──► SNS Topic: order-events
├──► SQS: payment-queue ──► Payment service
├──► SQS: inventory-queue ──► Inventory service
├──► SQS: notification-queue ──► Email service
└──► Lambda: analytics ──► Write to data lake

Each consumer gets its own copy of every message and processes independently.

Subscribers can filter messages by attributes — receive only what they care about:

{
"event_type": ["order_placed"],
"region": ["us-east", "us-west"]
}

Only messages matching the filter are delivered to that subscriber.

Terminal window
# Create topic
aws sns create-topic --name order-events
# Subscribe an SQS queue
aws sns subscribe --topic-arn arn:aws:sns:...:order-events \
--protocol sqs --notification-endpoint arn:aws:sqs:...:payment-queue
# Publish
aws sns publish --topic-arn arn:aws:sns:...:order-events \
--message '{"order_id": 123, "amount": 49.99}' \
--message-attributes '{"event_type":{"DataType":"String","StringValue":"order_placed"}}'

Like SQS FIFO — guaranteed ordering and deduplication. FIFO topics can only publish to FIFO SQS queues.

EventBridge is an event bus that routes events based on rules and patterns. It’s the most flexible option — think of it as SNS with content-based routing and native AWS service integration.

Event Source ──► Event Bus ──► Rule (pattern match) ──► Target
Rule ──► Target
Rule ──► Target

Every EventBridge event is a JSON envelope:

{
"version": "0",
"id": "abc-123",
"source": "com.myapp.orders",
"detail-type": "OrderPlaced",
"time": "2026-02-16T10:30:00Z",
"region": "us-east-1",
"account": "123456789012",
"detail": {
"order_id": 123,
"amount": 49.99,
"customer_id": "cust_456"
}
}

Rules match events by content and route them to targets:

{
"source": ["com.myapp.orders"],
"detail-type": ["OrderPlaced"],
"detail": {
"amount": [{"numeric": [">", 100]}]
}
}

This rule matches only OrderPlaced events where amount > 100.

TargetUse Case
LambdaProcess the event
SQSBuffer for async processing
Step FunctionsStart a workflow
SNSFan-out to subscribers
KinesisStream processing
API GatewayCall an HTTP API
ECS taskRun a container
CloudWatch LogsLog events for debugging
Another event busCross-account or cross-region routing
import boto3, json
events = boto3.client('events')
events.put_events(Entries=[{
'Source': 'com.myapp.orders',
'DetailType': 'OrderPlaced',
'Detail': json.dumps({
'order_id': 123,
'amount': 49.99,
'customer_id': 'cust_456'
}),
'EventBusName': 'default'
}])

Many AWS services publish events to EventBridge automatically:

ServiceExample Event
EC2Instance state change (running → stopped)
ECSTask state change
S3Object created (via EventBridge notification)
CodePipelinePipeline execution state change
HealthAWS service health events
GuardDutySecurity findings
{
"source": ["aws.ec2"],
"detail-type": ["EC2 Instance State-change Notification"],
"detail": {
"state": ["terminated"]
}
}

EventBridge replaces CloudWatch Events for cron-like schedules:

Terminal window
# Run a Lambda every hour
aws events put-rule --name hourly-cleanup \
--schedule-expression "rate(1 hour)"
# Cron: weekdays at 9 AM UTC
aws events put-rule --name daily-report \
--schedule-expression "cron(0 9 ? * MON-FRI *)"
ScenarioUse
Simple task queue (one producer → one consumer)SQS
Fan-out one event to multiple consumersSNS + SQS
Content-based routing (different events → different targets)EventBridge
React to AWS service eventsEventBridge
Cron / scheduled tasksEventBridge
High-throughput, order-sensitiveSQS FIFO
Email / SMS notificationsSNS
Complex event-driven microservicesEventBridge
  • SQS is a queue (point-to-point). Use for task processing, buffering, and decoupling. Always enable long polling and set up a dead-letter queue.
  • SNS is pub/sub (fan-out). Use with SQS for the fan-out pattern — one event triggers multiple independent consumers.
  • EventBridge is an event bus with content-based routing. Use for event-driven architectures, AWS service events, and scheduled tasks.
  • All three integrate natively with Lambda — no polling code needed.
  • SNS + SQS fan-out is the most common pattern: SNS broadcasts, each SQS queue buffers for its consumer.