A team migrates a blocking REST client to Spring WebFlux's reactive `WebClient` to "get backpressure for free." Is that a safe assumption, and where does the Reactive Streams protocol's `request(n)` actually prevent overload that a bounded buffer inside the same pipeline would not?
It's not a safe assumption, and it's a common way to ship a service that's "reactive" in name but still absorbs unbounded load, just with the buffer moved one layer down and out of sight. Reactive Streams' core rule is that a Publisher may not emit an item until a Subscriber has explicitly requested it via subscription.request(n) — the decision moves to before the item is produced, not after. That's structurally different from a bounded queue, which still has to accept an item and then decide what to do with it (hold it, block, or reject); a Reactive Streams pipeline that's actually honouring demand never produces the unwanted item onto the wire in the first place. The gap is that request(Long.MAX_VALUE) — "effectively unbounded demand" — is explicitly legal under the spec, and several common patterns issue it without the author realising: a naive .subscribe(item -> ...) overload, or a collecting operator like .collectList() on an unbounded source. Code built that way is still asynchronous and composed with reactive operators, but the backpressure protocol has been switched off, and the pipeline is exactly as exposed to unbounded growth as a plain LinkedBlockingQueue — just wearing reactive syntax.