Queues make systems look healthy after capacity has already been lost.
Requests are accepted, producers receive acknowledgements, dashboards stay green, and the backlog quietly converts a capacity problem into a time problem. By the time queue depth triggers an alert, the oldest work may already be too stale to matter and recovery may require hours of perfect operation.
The dangerous architecture is not “using a queue.” It is accepting work without a declared limit on how much delay, memory, and recovery debt the business is willing to own.
A queue stores promises #
Every queued item is a promise to spend future capacity. If arrival rate is λ and sustainable completion rate is μ, then while λ > μ, backlog grows at approximately:
backlog growth per second = λ - μIf 1,500 jobs arrive per second and workers sustainably finish 1,200, ten minutes creates 180,000 pending jobs. After traffic returns to 1,000 per second, only 200 jobs per second of spare capacity remain. Catch-up takes 900 seconds—another fifteen minutes—assuming no retries, poison messages, or reduced efficiency under load.
This is why depth alone is a weak signal. The more useful metrics are:
- age of the oldest useful item;
- estimated drain time at current spare capacity;
- arrival and completion rate separately;
- percentage of work already beyond its business deadline;
- retry and redelivery rate;
- hot partition or tenant skew.
A backlog of one million thumbnail jobs may be harmless. A backlog of 200 password-reset emails may already violate the product promise.
Bound the queue with a business deadline #
“Unbounded” is simply a capacity decision delegated to memory, disk, or the broker administrator.
Define queue limits in three dimensions:
- Count or bytes — the resource ceiling.
- Age — how long work remains useful.
- Recovery time — how long the organization accepts degraded service after load normalizes.
Attach an expiry or logical deadline to each item. A consumer should reject stale work before performing an expensive side effect:
{
"jobId": "quote-72a9",
"createdAt": "2026-08-24T06:29:12Z",
"executeBefore": "2026-08-24T06:29:42Z",
"priority": "interactive"
}Discarding work can be the most correct behavior. Recomputing a 20-minute-old recommendation or sending an expired one-time password does not restore correctness; it consumes recovery capacity.
Admission control belongs before expensive work #
Overload control is most effective where the system still has a choice. Once a request has acquired a database connection, loaded a model, or produced five downstream messages, rejecting it saves less.
Admission can be based on:
- concurrency rather than requests per second;
- estimated cost classes;
- tenant quotas;
- queue age and projected drain time;
- downstream saturation;
- priority and business criticality.
Concurrency is often the stronger primitive because it tracks work retained in the system. One service may handle 5,000 fast requests per second but collapse with 300 slow concurrent requests.
admit if:
inflight_cost + request_cost <= capacity_budget
and tenant_inflight < tenant_limit
and oldest_queue_age < recovery_thresholdThe cost estimate does not need to be perfect. Separating a one-row lookup from a report export is already better than pretending all requests cost one token.
Backpressure must cross ownership boundaries #
Slowing one consumer does not create backpressure if upstream producers keep accepting demand. The pressure signal must travel far enough to change admission.
Possible signals include:
- synchronous
429or503responses with retry guidance; - reduced consumer credit or pull rate;
- bounded channel writes that block producers;
- explicit broker quota errors;
- a control-plane signal that lowers per-tenant concurrency;
- UI feedback that disables or defers nonessential actions.
Backpressure is not “the queue is getting longer.” It is a closed loop in which downstream scarcity causes upstream demand to reduce.
Be careful when automatically scaling consumers. More workers may improve throughput, or they may move the bottleneck into the database and multiply connection pressure. Scale against the constrained resource, not queue depth alone.
Load shedding protects useful work #
Google’s SRE guidance treats overload as normal and recommends rejecting some work so the system can continue serving the rest. That requires a policy before the incident.
A practical priority order might be:
1. authentication and safety controls
2. committed financial or state transitions
3. interactive reads
4. customer notifications
5. indexing and analytics
6. speculative enrichmentThe exact order is a product decision, not an infrastructure default. During overload, pause speculative enrichment before delaying a committed payment. Reserve capacity for control operations so operators can still cancel, drain, or reconfigure work.
Do not silently drop accepted work. Either reject before acceptance, persist a visible terminal outcome, or expose reconciliation. The user must be able to distinguish “not accepted” from “accepted but delayed.”
Retry queues can become permanent storage #
Retries need a bounded attempt count, a next-attempt time, and a terminal owner. Immediate redelivery of a poison event can consume an entire partition.
attempt 1 -> short jittered delay
attempt 2 -> longer delay
attempt 3 -> quarantine with reason and ownerA dead-letter queue is not a solution if nobody drains it. Track oldest age, volume by failure class, and resolution time. Store enough context to reproduce the failure without leaking secrets into an operational dumping ground.
For ordered streams, moving one event aside may violate aggregate order. Quarantine the affected key or partition while allowing unrelated keys to progress; then make the business impact visible.
Run the recovery calculation before launch #
Capacity tests usually ask, “What peak can we process?” Add three harder tests:
- What happens when a dependency runs at 40% capacity for fifteen minutes?
- How long does the backlog take to drain after recovery?
- Can critical traffic meet its objective while background work drains?
Inject slow consumers, skew one tenant, expire work, and restart workers during redelivery. Confirm that autoscaling does not exhaust database connections and that overload responses do not trigger aggressive client retries.
The target is not an infinite buffer. It is controlled degradation with a calculable path back to normal.
CTO review questions #
- What promise does accepting a queued item make?
- At what age does the item lose business value?
- What resource ultimately limits consumer throughput?
- How is downstream pressure communicated to the original producer?
- Which work is shed first, and who approved that priority?
- How long will recovery take after a realistic partial-capacity incident?
- Who owns quarantined work?
Queues separate arrival from execution. They do not create capacity. A production design makes the hidden debt visible, bounds it, and refuses new promises before the old ones become impossible to keep.