Backend Development › Queues & Async Processing
Producer and Consumer
The two sides of a queue.
Also known as: producer and consumer, producer consumer, producer-consumer
Producer and consumer is the pattern of decoupling the component that creates work from the component that does it, connected by a queue. The producer enqueues a message and moves on; a consumer dequeues and processes it. Neither knows much about the other.
producer ──enqueue──▶ [queue] ──dequeue──▶ consumer
The value is loose coupling and rate-matching:
- Independent scaling — add consumers to handle more volume without touching the producer.
- Burst absorption — the queue holds a spike; consumers work through it at their own pace.
- Isolation — a slow or crashed consumer doesn’t break the producer; the queue buffers.
It’s the base pattern under job queues, message brokers, and much of asynchronous architecture.
The classic mistakes:
- Unbounded queues. Without a bound, a fast producer and slow consumer grow the queue until memory or disk fills. The backlog must be visible and handled (see queue depth and backpressure).
- No backpressure to the producer. If consumers fall behind, the producer should eventually feel it (slow down, reject, or shed) rather than pushing forever. Otherwise the queue is just deferred failure.
- Non-idempotent consumers. Messages can be redelivered; a consumer that assumes exactly-once will double-process (see idempotence).
- Assuming order. Unless the queue guarantees it, consumers may see messages out of order; don’t rely on it (see message ordering).
- No visibility. A silent growing backlog is a brewing outage. Monitor queue depth, processing rate and failures.
- One consumer for a critical queue. A single consumer is a bottleneck and a single point of failure; run several (where order allows) for scale.
- Confusing it with request/response. Producer/consumer is asynchronous; the producer doesn’t wait for a reply. If you need a response, that’s a different pattern (request/reply over the queue).
How to use it: bound the queue, add backpressure to the producer, make consumers idempotent, monitor depth, and scale consumers to the load. It’s the simplest way to make a system asynchronous and resilient, and the mental model for nearly everything built on queues. See worker and message broker.