Queues & Background Jobs
The pattern that keeps a user-facing request fast by moving the slow part somewhere else.
5.10.1Definition
A queue holds units of work — jobs — to be processed asynchronously by a separate worker process, rather than inline within the request that created them. A user action (placing an order, uploading a video) enqueues a job; a worker picks it up moments later and performs the slow part (sending a confirmation email, transcoding a video) without the original request waiting on it.
5.10.2Why It Exists
Some work is simply too slow to perform within a single HTTP request without degrading user experience or risking a timeout — sending email (5.8), processing images, generating reports. Queues exist to decouple "the request finished" from "the work is done," letting the user get a fast response while the slow work completes in the background, often with automatic retries if it fails.
5.10.3Core Components
- Producer — the part of the application that enqueues a job (e.g., the checkout handler enqueuing an "send receipt" job).
- Queue/broker — the storage layer holding pending jobs (Redis, SQS, RabbitMQ), typically backed by the same infrastructure used for caching (5.9).
- Worker — a separate process that pulls jobs from the queue and executes them, scaled independently from the web servers handling requests.
- Retry & dead-letter handling — failed jobs retried with backoff, eventually routed to a dead-letter queue for manual inspection rather than retried forever.
5.10.4Common Mistakes
- Performing slow work synchronously inside the request handler, causing the user to wait — or the request to time out — for work that didn't need to block the response at all.
- No retry or dead-letter strategy, silently losing jobs that fail once instead of retrying transient failures or surfacing permanent ones.
- Jobs that aren't idempotent, causing a retried job (after a transient failure) to duplicate its effect — sending two receipt emails instead of one.
5.10.5Best Practices
- Move any operation slower than roughly 200–300ms, or any operation with an external dependency, out of the synchronous request path.
- Design job handlers to be idempotent so retries are always safe.
- Monitor queue depth and dead-letter volume as a standard operational metric (5.13).