One-liner: A message queue decouples services by letting a producer drop messages into a queue, where consumers pick them up asynchronously β neither needs to be available at the same time.
π The Problem: Tight Coupling
User places order β
[Order Service] β calls [Payment Service] β waits β
β calls [Email Service] β waits β
β calls [Inventory Service] β waits β
All done! (3s total, 3 failure points)
Problems:
- High latency β user waits for every downstream service
- Cascading failure β if Email service is down, order fails
- Tight coupling β Order service knows about all downstream services
- No retry logic β failures are permanent
π‘ The Solution: Message Queue
User places order β [Order Service] β DROP message in queue β RESPOND (fast!)
β
[Queue]
/ | \
[Payment] [Email] [Inventory] β process at their own pace
Benefits:
- Decoupling β services don't know about each other
- Resilience β downstream service can be down; message waits in queue
- Load leveling β queue absorbs traffic spikes
- Retry β failed processing retried automatically
π Queue Concepts
Producer & Consumer
[Producer] β push message β [Queue] β pull message β [Consumer]
- Producer: Creates and sends messages
- Consumer: Reads and processes messages
- Queue: Durable buffer between them
Message Lifecycle
1. Producer sends message β Queue stores it
2. Consumer polls queue β Queue marks message as "in-flight" (invisible to others)
3. Consumer processes β Success: Consumer deletes message
β Failure: After visibility timeout, message reappears
Visibility Timeout
Consumer pulls message β message hidden for 30 seconds
If consumer crashes β 30 seconds later, message reappears β another consumer picks it up
If consumer succeeds β consumer deletes message β gone forever
βοΈ AWS SQS (Simple Queue Service)
Standard Queue
- Unlimited throughput
- At-least-once delivery β message may be delivered more than once!
- Best-effort ordering β no strict FIFO
FIFO Queue
- Exactly-once processing β deduplication
- Strict ordering β first in, first out
- Limited throughput β 300 msg/sec (or 3000 with batching)
SQS Key Concepts
Message retention: Up to 14 days (default: 4 days)
Visibility timeout: How long consumer has to process (default: 30s)
Dead Letter Queue: Where failed messages go after N retries
Max message size: 256 KB
SQS + Lambda (Serverless Consumer)
[SQS Queue] ββtriggersβββΊ [Lambda Function]
(auto-scales to process backlog)
π Queue Patterns
Work Queue (Task Distribution)
[Producer] β [Queue] β [Worker 1]
β [Worker 2]
β [Worker 3]
Each message processed by exactly ONE worker
Use case: Image resizing, email sending, PDF generation
Fan-out via Multiple Queues
[Event] β [SNS Topic] β [Queue A] β [Consumer A]
β [Queue B] β [Consumer B]
β [Queue C] β [Consumer C]
Each consumer gets a copy of the message. (See: SNS/Pub-Sub)
Priority Queue
High priority queue β processed first by consumers
Low priority queue β processed when high is empty
β»οΈ Dead Letter Queue (DLQ)
When a message fails to process after N retries β move to DLQ:
[Queue] β [Consumer fails 3 times] β [DLQ]
β
Ops team inspects,
fixes bug, redrives
// SQS Redrive Policy
{
"deadLetterTargetArn": "arn:aws:sqs:us-east-1:123:my-dlq",
"maxReceiveCount": 3 // after 3 failures, move to DLQ
}
β οΈ Idempotency β Critical Requirement
Standard queues deliver at-least-once. Your consumer MUST be idempotent:
Message: "charge user 42 for $99"
β Non-idempotent: Just run the charge every time β user charged twice!
β
Idempotent: Check if orderId already processed β skip if yes
async function processPayment(message) {
const { orderId, userId, amount } = message;
// Check idempotency key
const alreadyProcessed = await redis.get(`payment:${orderId}`);
if (alreadyProcessed) return; // skip duplicate
await chargeUser(userId, amount);
await redis.setex(`payment:${orderId}`, 86400, "1"); // mark done
}
π SQS vs Other Queues
| Feature | AWS SQS | RabbitMQ | Apache Kafka |
|---|---|---|---|
| Type | Managed cloud | Self-hosted broker | Distributed log |
| Retention | 14 days | Until consumed | Configurable (forever) |
| Ordering | Best-effort/FIFO | Per-queue | Per-partition |
| Replay | β | β | β (replay from offset) |
| Throughput | Very high | High | Very high |
| Use case | Decoupling tasks | Complex routing | Event streaming |
π¨ Diagram
The diagram shows:
- Producer β Queue β Multiple consumers
- Visibility timeout flow (in-flight β reappear)
- Dead Letter Queue after max retries
- Fan-out via SNS β multiple queues
π Key Takeaways
- Queues decouple services and absorb traffic spikes
- Visibility timeout ensures messages aren't lost if a consumer crashes
- Always implement idempotent consumers with SQS Standard
- DLQ is essential for debugging failed messages
- Use FIFO when order matters; Standard when throughput matters
Top comments (0)