High Level Design

Message Queues

How message queues decouple producers and consumers, core components, edge cases like poison messages and duplicates, and popular implementations.

August 10, 2026

A Message Queue is an asynchronous communication mechanism where producers send messages to a queue and consumers process them independently, enabling decoupled and resilient systems.

Pain Points Solved#

  • Synchronous calls cause high latency and cascading failures
  • Traffic spikes overwhelm downstream services
  • Tight coupling blocks independent scaling
  • Retries and failure handling are complex

Use Cases#

  • Background job processing (emails, notifications)
  • Order processing pipelines
  • Payment retries
  • Event-driven microservices

Architecture#

Message queue architecture

Core Components#

ComponentRole
ProducerPublishes messages
QueueBuffer holding messages
ConsumerProcesses messages
BrokerManages queues and delivery
Acknowledgement (Ack)Confirms successful processing
Dead Letter Queue (DLQ)Stores messages that failed after max retries

Flow#

  1. Producer sends message to Queue
  2. Queue persists the message
  3. Consumer polls or subscribes
  4. Consumer processes the message
  5. Message is acknowledged and removed

Key idea: Work is buffered and processed asynchronously.


Trade-offs#

ProsCons
Loose couplingLimited message replay
Better fault toleranceOrdering guarantees can be weak
Load levelingDebugging async flows is harder
Easy retriesThroughput lower than log-based systems (Kafka)

ToolBest For
RabbitMQRouting, exchanges, low latency
Amazon SQSFully managed, simple scaling
ActiveMQJMS-based enterprise use

Edge Cases#

1. Poison Messages Blocking Consumers#

A malformed/invalid message that always fails processing, no matter how many retries.

Problem: Consumer keeps retrying → queue head is blocked → throughput drops to zero.

Solutions:

  • Retry limit (max retry count)
  • Exponential backoff to avoid tight retry loops
  • Dead Letter Queue (DLQ) after N failures

2. Duplicate Message Processing#

The same message is processed more than once.

Happens due to: Consumer crashes after processing but before ack; network timeout → broker resends.

Problem: Double charges, duplicate emails.

Solutions:

  • Idempotent consumers — track processed message IDs
  • Upserts instead of inserts

3. Message Ordering Violations#

Messages processed out of the order they were produced.

Happens due to: Multiple parallel consumers; retries reorder; unordered queues.

Solutions:

  • Partition by key (orderId, userId)
  • Single consumer per key
  • FIFO queues (with reduced throughput)
  • Sequence numbers + reordering logic

4. DLQ Growth Monitoring#

A Dead Letter Queue stores permanently failed messages. DLQ growth = silent data loss.

Failure modes: DLQ fills up unnoticed; same bug keeps producing bad messages; no alerting.

Solutions:

  • Monitor DLQ size and rate
  • Alert on abnormal growth
  • Build reprocessing pipelines
  • Store failure reason and stack trace in DLQ message

Use a message queue when you need asynchronous task processing, retries, and buffering — but do not need event replay.

Queues are for tasks, not event history. Use Kafka if you need replay.