Backpressure is a feature, not a failure
Why a system that says no under load is healthier than one that swallows everything and falls over.
Every system has a limit. The only choice you get is whether that limit is something you designed or something you discover at 2am. Backpressure is how you design it.
The failure mode nobody plans for
The default behavior of most services is to accept work unconditionally. A request arrives, you allocate memory, you queue it, you promise to get to it. This feels generous. It is actually a slow-motion outage.
When arrival rate exceeds service rate, queues grow. Growing queues mean growing latency, and growing latency means clients time out and retry, which increases the arrival rate further. The system does not gently slow down. It falls off a cliff.
Saying no on purpose
Backpressure is the practice of pushing the limit back toward the caller instead of absorbing it silently. A bounded queue is the simplest form:
sem := make(chan struct{}, maxInFlight)
func handle(w http.ResponseWriter, r *http.Request) {
select {
case sem <- struct{}{}:
defer func() { <-sem }()
process(w, r)
default:
http.Error(w, "busy, retry shortly", http.StatusServiceUnavailable)
}
}The default branch is the whole point. When the system is full, it rejects fast with a clear signal, instead of accepting work it cannot finish.
What good backpressure looks like
- Bounded everything. Queues, connection pools, and worker counts all have ceilings you chose.
- Fast rejection. A quick 503 is kinder than a slow timeout. The client can react.
- Load shedding by priority. When you must drop work, drop the cheapest and least important first.
A system that says no is not broken. It is telling you the truth about its capacity, early enough for you to do something about it.