Backpressure, Explained With a Coffee Shop
Queues, load shedding, and what happens when producers outrun consumers.
The Problem
Backpressure is what stops a fast producer from overwhelming a slower consumer. Without it, your API accepts more work than workers, databases, or downstream services can finish, and the system fails after the queue is already too large.
Why It Matters
Backpressure is the difference between a system that degrades and a system that collapses. A service under pressure should protect its most important work, reject work it cannot finish, and recover quickly when load drops.
This is common in real systems that use Kafka, RabbitMQ, SQS, Redis streams, HTTP APIs, and batch workers. The tool changes, but the core problem is the same: producers can often create work faster than consumers can complete it.
Project Example
An order service receives 2,000 checkout requests per second during a sale, but the payment provider can handle only 600 per second. If the API accepts all requests and blindly queues payment jobs, customers wait for stale jobs that will time out anyway.
Implementation Example
if (queue.oldestMessageAgeSeconds("payments") > 30) {
return res.status(503).json({
error: "checkout_temporarily_busy",
retryAfterSeconds: 20,
});
}
This is not just defensive coding. It is product behavior. A fast, honest failure lets the client retry later instead of waiting two minutes for a payment job that will no longer be useful.
Implementation Checklist
- Put a hard max on queue depth or oldest-message age.
- Return
429or503when the system is saturated. - Use short request deadlines and pass them to downstream calls.
- Separate high-priority work from background work.
- Alert on queue age, not only queue size.
- Add dead-letter queues for poison messages.
- Stop retrying when the business deadline has passed.
- Document which workloads can be dropped and which must be durable.
Production Notes
For user-facing APIs, the oldest message age is often a better alert than queue depth. A queue of 10,000 fast jobs may be fine. A queue of 100 jobs that are each 20 minutes old may be a customer incident.
In stream processing, backpressure should propagate upstream. If the consumer is slow because Postgres is overloaded, adding more consumers can make the database even slower.
Common Mistakes
- Treating a queue as infinite capacity.
- Scaling consumers without checking database and API limits.
- Retrying everything immediately during an outage.
- Measuring only average latency while p99 is burning users.
- Hiding overload until every dependency is saturated.
- Using one queue for urgent user work and slow background work.
Summary
Backpressure is a contract: the system says "not now" before accepting work it cannot complete. Real projects need bounded queues, deadlines, priority, and clear load-shedding behavior.
The weekly engineering digest
Production-grade engineering writing in your inbox. No spam, unsubscribe anytime.