Backpressure in Spring WebFlux, explained with a leaky bucket
Reactive code gets a reputation for being hard, and most of that reputation comes from one word: backpressure. It sounds like plumbing, and honestly, the plumbing metaphor is the fastest way to understand it.
A consumer that can't keep up
Imagine a producer pouring events into a bucket and a consumer draining it. If the
producer pours faster than the consumer drains, the bucket overflows — in software terms,
you get unbounded memory growth and, eventually, an OutOfMemoryError. Backpressure is
the consumer telling the producer "slow down, I'll ask for more when I'm ready."
In Reactor, that conversation is built into the Publisher/Subscriber contract. A
subscriber calls request(n) to signal how many items it can handle:
Flux.range(1, 1_000_000)
.onBackpressureBuffer(256) // bounded buffer, not infinite
.publishOn(Schedulers.parallel())
.subscribe(new BaseSubscriber<>() {
@Override
protected void hookOnSubscribe(Subscription s) {
request(1); // ask for one to start
}
@Override
protected void hookOnNext(Integer value) {
handle(value);
request(1); // ask for the next only when done
}
});The subscriber pulls one item at a time. The producer can't get ahead of it, and the buffer is explicitly bounded — overflow becomes a decision (drop, error, latest) instead of a surprise.
Strategies you actually choose between
| Operator | What it does when overwhelmed |
|---|---|
onBackpressureBuffer |
Queues items (optionally bounded) |
onBackpressureDrop |
Discards items the consumer can't take |
onBackpressureLatest |
Keeps only the most recent item |
There's no universally correct choice — a metrics stream might prefer latest, an audit
log must buffer and never drop. The point is that Reactor makes you decide, and that
decision is where reliability lives.
When you don't need any of this
If your pipeline is request/response — one HTTP call in, one out — backpressure rarely matters; demand is naturally bounded by the single result. It earns its keep with streams: server-sent events, Kafka consumers, file processing, anything where a fast source meets a slower sink. Reach for it there, and leave the ceremony out of the simple paths.
Comments
Comments are powered by GitHub Discussions and aren't configured yet.