MESSAGING & EVENT-DRIVEN ARCHITECTURE / SYSTEM CONCEPT BRIEF

Message queues

A message queue is a buffer between services: producers put messages on the queue, and consumers take them off and process them, at their own pace.

BeginnerPhase 06 / Topic 1 of 18RequirementsTrade-offsFailure modes
01

Overview

A message queue is a buffer between services: producers put messages on the queue, and consumers take them off and process them, at their own pace. This decouples the two sides in time (the consumer can be down or slow), in scale (add consumers independently), and in failure (a crash does not lose work that is still in the queue).

Queues turn synchronous chains into asynchronous workflows. Instead of making the user wait for an email to be sent and a PDF to be generated, the API enqueues jobs and returns immediately. Each message is normally processed by one consumer, and it is removed only after the consumer acknowledges it, so failed work is retried.

A restaurant order rail

Waiters clip order tickets on a rail; cooks take the next ticket when ready. Waiters do not wait for food to be cooked before taking more orders, and during a rush, tickets simply pile up until cooks catch up.

02

When to use it

  • Slow or unreliable work that should not block user requests (emails, images, reports).
  • Absorbing traffic spikes (load leveling).
  • Decoupling services so one being down does not break another.
  • Distributing work across a pool of workers.
03

Where it shows up in interviews

Async background jobs

Recognize it when: the request triggers slow work.

  • Design a video upload pipeline
  • Design an email notification system
Load leveling

Recognize it when: traffic spikes exceed downstream capacity.

  • Design a flash sale system
  • Design a ticketing queue
04

Where it is used in real software

Amazon SQS

Fully managed queue used for decoupling microservices; standard queues scale nearly without limit.

Sidekiq, Celery, BullMQ

Background job frameworks on top of Redis or RabbitMQ for Ruby, Python, and Node.

Uber and Shopify

Use queues and streams for payments, dispatch, and order processing to absorb peak load.

05

Key terms

Producer / consumer
Sends messages / receives and processes them.
Acknowledgment
Consumer confirms processing so the message is deleted.
Visibility timeout
Message hidden from others while one consumer works on it.
Backlog / queue depth
Number of messages waiting.
Competing consumers
Many workers share one queue; each message goes to one.
06

How it works, step by step

  1. 1
    Producer sends a message

    Small payload with IDs, not large blobs.

  2. 2
    Queue stores it durably

    Replicated so broker failures do not lose it.

  3. 3
    Consumer receives it

    Message becomes invisible to other consumers.

  4. 4
    Consumer processes and acks

    The queue deletes the message.

  5. 5
    Failures are retried

    No ack before timeout: redelivered; too many failures: dead-letter queue.

Queue decoupling a web API from workers
Step 1 / 4
User
API
Queue
Worker 1
Worker 2

STEP 1The user uploads a video. The API stores the file and creates a job.

07

Synchronous vs queued signup

Signup sends a welcome email, creates a CRM record, and resizes an avatar

Step 1 / 4
AspectSynchronousWith a queue
User-facing latency~2.5 s (sum of all steps)~100 ms (save user + enqueue)
Email provider downSignup failsEmails retried later
Traffic spikeEverything slowsBacklog grows, workers catch up
ScalingScale all togetherScale workers independently

NOWAspect: User-facing latency | Synchronous: ~2.5 s (sum of all steps) | With a queue: ~100 ms (save user + enqueue)

Queues trade immediate completion for resilience and responsiveness; the UI must handle 'still processing' states.

08

Implementation

import { SQSClient, SendMessageCommand, ReceiveMessageCommand, DeleteMessageCommand } from "@aws-sdk/client-sqs"; const sqs = new SQSClient({});const QueueUrl = process.env.EMAIL_QUEUE_URL!; // Producerawait sqs.send(new SendMessageCommand({ QueueUrl, MessageBody: JSON.stringify({ type: "welcome", userId: "42" }) })); // Consumer loopwhile (true) {  const { Messages = [] } = await sqs.send(new ReceiveMessageCommand({    QueueUrl, MaxNumberOfMessages: 10, WaitTimeSeconds: 20, VisibilityTimeout: 60, // long polling  }));  for (const msg of Messages) {    try {      await sendWelcomeEmail(JSON.parse(msg.Body!));        // must be idempotent      await sqs.send(new DeleteMessageCommand({ QueueUrl, ReceiptHandle: msg.ReceiptHandle! }));    } catch (err) {      console.error("will be retried after visibility timeout", err);    }  }}
09

Complexity and performance

Enqueue / dequeueO(1)

Milliseconds.

Workers neededarrival rate x processing time

Little's Law.

10

Trade-offs

Responsiveness vs immediacy

Users get fast responses but results arrive later; design status endpoints or notifications.

Decoupling vs visibility

Asynchronous flows are harder to trace and debug; add correlation IDs and tracing.

11

Variants and related techniques

Priority queues

Separate queues for urgent and bulk work.

Delay queues

Messages become visible after a delay, for scheduled retries.

FIFO queues

Ordered, exactly-once processing within a group, at lower throughput.

12

Common mistakes

  • Non-idempotent consumers.

    Fix: Messages can be delivered more than once; deduplicate.

  • Huge messages.

    Fix: Store payloads in object storage and send a reference.

  • No monitoring of queue age.

    Fix: Alert on the age of the oldest message, not just depth.

13

Interview questions

Why put a queue between the API and workers?

It decouples request handling from slow work, lets the API respond quickly, absorbs traffic spikes, allows independent scaling of workers, and retries failed work without losing it.

How do you size the worker pool?

Workers = arrival rate x average processing time (Little's Law), plus headroom; auto scale on queue depth or oldest-message age.

14

Practice problems

ProblemDifficultyWhat it trains
Move email sending to a queueEasyAsync processing.
Design a video transcoding pipelineMediumQueues and workers.