Skip to content
man glossary/backpressure

glossary define backpressure

Name

Backpressure

Backpressure is flow control in which a slow downstream stage makes upstream producers slow down, so queues and memory stay bounded.

Synopsis

Back pressure, Back-pressure, Flow control

Section

Reliability & scale

Level

practitioner

▍

Reviewed

Producer faster than the number? Watch the queue grow

40× slow motionService time S = 100 ms per job on average · 8 workers

Queue diagram: 24 sends waiting, 8 of 8 workers busy, 8 done.

Backlog
∞
grows without bound
Throughput
80/s
ceiling 80/s with 8 workers
Average wait
∞
keeps growing
Utilisation ρ
1.25
≈ 8 of 8 busy
100 sends/s
8

ρ = λ × S ÷ c = 100/s × 100 ms ÷ 8 = 1.25

Backlog grows without bound. ρ = 1.25 ≥ 1: sends arrive faster than 8 workers can finish them. Add workers, speed up each job or slow the producer.
A campaign producer adds 100 sends a second; eight workers at 100 ms per Cloud API call finish only 80. Watch the queue grow, then drag the arrival rate below 80 — what backpressure does to the producer.

Utilisation is at or above 1: the backlog grows without bound.

Description

What is backpressure?

Backpressure is the mechanism by which a slower stage in a pipeline pushes back on the faster stages feeding it. When a consumer cannot keep up, it stops accepting new work — a bounded Message Queue refuses inserts, a stream stops reading, an API answers 429 or 503 — and the producer responds by slowing down, pausing or holding work at the source. Without it, the gap between arrival rate and processing rate accumulates as an ever-growing queue, rising memory and latency, and eventually a crash that loses everything in flight.

In queueing terms, if jobs arrive at λ per second, each takes S seconds and there are c workers, utilisation is ρ = λ × S ÷ c. Below 1 the queue fluctuates but drains; at or above 1 it grows without limit, however large the buffer. Backpressure keeps ρ below 1 by lowering λ at the source. In a WhatsApp send pipeline the hardest downstream limit is the phone number's Throughput — 80 messages per second by default, 1,000 after an automatic upgrade — and pushing past it returns Error 130429 (Rate Limit Hit) instead of going faster.

Backpressure is flow control that slows work down; it discards nothing. Load Shedding drops or defers low-priority work when the system is saturated, and Rate Limiting is an externally imposed cap, such as Meta's throughput or an API quota. Good pipelines combine all three: a rate limiter paces sends to the number's limit, backpressure carries that pace upstream to campaign schedulers and CSV importers, and load shedding protects OTPs if the backlog grows anyway.

Key takeaways

  • Backpressure is a signal from a slow stage telling producers to slow down, so work waits at the source instead of piling up without bound.
  • If producers outrun consumers for long, a queue grows forever: utilisation ρ = λ × S ÷ c must stay below 1.
  • Backpressure slows work, load shedding drops work, and rate limiting is a cap imposed from outside.
  • A WhatsApp number's throughput — 80 messages per second by default — is a hard downstream limit your send pipeline must respect.
  • Bound every queue and buffer, and decide what happens when it is full: block, reject with 429 or 503, or shed low-priority work.

Why it matters

Why does backpressure matter?

Many messaging outages that start with "the queue filled up" are missing backpressure. A campaign importer that reads a two-million-row CSV as fast as the disk allows, or a webhook handler that accepts events faster than the CRM sync can write them, turns a temporary mismatch into an out-of-memory crash or a backlog that delays OTPs behind marketing. Propagating "slow down" back to the source keeps memory flat, latency predictable and failures local.

Mechanics

How does backpressure work?

  1. step 1 — Bound every buffer

    Give each queue, channel and in-memory array a maximum size or byte budget. An unbounded buffer is not a buffer; it is a deferred crash.

  2. step 2 — Let consumers signal capacity

    Consumers pull work when they are ready — prefetch counts, highWaterMark on streams, credit-based flow — instead of having work pushed at them regardless of load.

  3. step 3 — Propagate the signal upstream

    When the send queue is full, the campaign scheduler pauses enqueueing; when your own API is saturated, it answers 429 or 503 with Retry-After so callers back off.

  4. step 4 — Pace to the hardest limit

    Run sends below the number's throughput — say 70 of 80 messages per second — with the token bucket algorithm, so the Cloud API is never the component applying backpressure through 130429 errors.

  5. step 5 — Watch lag and saturation

    Track Consumer Lag — queue depth and the age of the oldest message — and worker utilisation. A sustained rise means producers outrun capacity: add workers if the bottleneck can scale, slow the source if it cannot.

Usage

Backpressure in code

// Stream a contacts CSV into the send queue without loading it all into memory.
import { createReadStream } from "node:fs";
import { Writable } from "node:stream";
import { pipeline } from "node:stream/promises";
import { parse } from "csv-parse";
const HIGH_WATER = 20_000; // pause the import above this many waiting jobs
const LOW_WATER = 10_000; // resume once the workers drain below this
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const toQueue = new Writable({
objectMode: true,
highWaterMark: 500, // rows buffered before the parser is paused
async write(row, _enc, done) {
try {
if ((await sendQueue.count()) > HIGH_WATER) {
while ((await sendQueue.count()) > LOW_WATER) await sleep(1_000);
}
await sendQueue.add("template-send", { to: row.phone, params: [row.name, row.result] });
done(); // calling done() late is the backpressure signal
} catch (err) {
done(err);
}
},
});
await pipeline(createReadStream("results.csv"), parse({ columns: true }), toQueue);

The parser stops reading the file whenever the writer has not called done(), so a full queue pauses the whole pipeline back to the disk.

Properties

Backpressure: key facts and limits

Stability condition
ρ = λ × S ÷ c < 1
Default Cloud API throughput
80 messages per second per number
Upgraded throughput
1,000 messages per second (automatic, if eligible)
Over-limit error
130429 (rate limit hit)
Common signals
Bounded queue full, stream pause, HTTP 429/503 with Retry-After
Node.js streams
write() returns false above highWaterMark; wait for 'drain'

Example

Example: Result day at a Lucknow coaching institute

A coaching institute in Lucknow sends exam results to 300,000 students with a utility template. Its old importer read the whole CSV into memory and enqueued every row in seconds, while the send workers, capped by the number's 80 messages per second, needed over an hour — so the queue ballooned until the Redis node ran out of memory mid-run. The rebuilt importer streams the file and pauses whenever more than 20,000 jobs are waiting, resuming below 10,000. Memory stays flat, the run finishes in about 70 minutes at a steady 72 sends per second, and OTPs on their own queue are never delayed.

Caveats

Common mistakes with backpressure

  • Unbounded in-memory buffers

    Arrays, promise lists and queues with no limit hide the problem until memory runs out and every in-flight job is lost. Bound them and decide in advance what happens when they are full.

  • Scaling workers past the real bottleneck

    If the limit is the number's throughput or a CRM's write quota, more workers only produce more 130429s and 429s. Find the true constraint and pace to it.

  • Ignoring the signal in your own code

    In Node.js, ignoring stream.write() returning false, or looping over queue.add() without awaiting, are the classic leaks. Respect drain, await each insert, or batch with a limit.

  • Pushing back on the wrong traffic

    With one shared queue, a marketing import's backpressure also delays OTPs. Give each priority its own queue, following the bulkhead pattern, so a broadcast never slows authentication messages.

Notes

Best practices for backpressure

  • Alert on the age of the oldest queued job, not only on depth — age is what customers feel.
  • Use high and low watermarks (pause at 20,000, resume at 10,000) so producers do not flap on and off.
  • Send Retry-After with every 429 or 503 so well-behaved clients back off by the right amount.
  • Load-test with the producer deliberately faster than the consumer, and confirm memory stays flat.

Questions

Backpressure FAQs

What is the difference between backpressure and rate limiting?
Backpressure is a dynamic signal from a slow consumer; rate limiting is a fixed cap. A rate limiter enforces, say, 70 sends a second whatever happens, while backpressure slows producers whenever any downstream stage falls behind, by as much as needed.
Is backpressure the same as load shedding?
No. Backpressure slows producers so all work is eventually done; load shedding deliberately drops or defers some work to protect the rest. Apply backpressure first, and shed only low-priority traffic when the backlog still grows.
How does backpressure apply to the WhatsApp Cloud API?
The phone number's throughput is the downstream limit. Pace sends below 80 messages per second (or 1,000 after an upgrade) and let a full send queue pause your campaign scheduler, instead of discovering the limit through 130429 errors.
Can I apply backpressure to Meta's webhooks?
Only indirectly, because Meta decides when webhooks are sent. Acknowledge each one quickly into a durable queue; if you return errors or time out, Meta retries for up to seven days — backpressure in its crudest, slowest form.

See InfiQ pricing

Put Backpressure to work

InfiQ is an official Meta Business Partner. Start a 7-day free trial — no card needed — and see this running on your own number.