DEV Community

Cover image for Message Queues (SQS)
Gouranga Das Samrat
Gouranga Das Samrat

Posted on

Message Queues (SQS)

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

☁️ 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
Enter fullscreen mode Exit fullscreen mode

SQS + Lambda (Serverless Consumer)

[SQS Queue] ──triggers──► [Lambda Function]
                           (auto-scales to process backlog)
Enter fullscreen mode Exit fullscreen mode

🔀 Queue Patterns

Work Queue (Task Distribution)

[Producer] → [Queue] → [Worker 1]
                     → [Worker 2]
                     → [Worker 3]

Each message processed by exactly ONE worker
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

♻️ 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
Enter fullscreen mode Exit fullscreen mode
// SQS Redrive Policy
{
  "deadLetterTargetArn": "arn:aws:sqs:us-east-1:123:my-dlq",
  "maxReceiveCount": 3 // after 3 failures, move to DLQ
}
Enter fullscreen mode Exit fullscreen mode

⚠️ 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
Enter fullscreen mode Exit fullscreen mode
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
}
Enter fullscreen mode Exit fullscreen mode

📊 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)