WebFlux Reactive Patterns
Use WebFlux when the complete request path benefits from non-blocking I/O.
Dependencies and pipeline rules
- Use the dedicated Boot 4 WebFlux and WebFlux test starters.
- Return
MonoorFlux; never callsubscribe()in request-handling code. - Choose
flatMap,concatMap, or sequential composition according to ordering needs. - Keep JDBC, filesystem, and blocking SDK calls off Reactor event loops.
- Isolate unavoidable blocking work on
boundedElasticat the adapter boundary. - Apply timeouts to external calls and preserve cancellation.
Context and errors
- Put request-scoped metadata in Reactor
Context, notThreadLocal. - Configure observability context propagation deliberately.
- Translate domain failures centrally without swallowing cancellation.
- Use
onErrorResumeonly for a defined fallback and avoidonErrorContinue.
Persistence and streaming
- Use R2DBC for reactive database access.
- Bound fan-out concurrency according to downstream capacity.
- Define backpressure, buffering, and maximum in-memory sizes.
- Never collect an unbounded stream solely to simplify downstream code.
Testing
- Use
StepVerifierfor publisher behavior andWebTestClientfor contracts. - Test cancellation, timeout, empty results, errors, ordering, and backpressure.
- Detect blocking calls in tests when practical.
Examples
- See
examples/good-reactive-service.javaandexamples/bad-reactive-service.java.
Official sources
- Spring WebFlux: https://docs.spring.io/spring-framework/reference/web/webflux.html
- Reactor reference: https://projectreactor.io/docs/core/release/reference/
- Spring Data R2DBC: https://docs.spring.io/spring-data/relational/reference/r2dbc.html
Gotchas
- Agent adds MVC and WebFlux starters accidentally - choose the intended web stack.
- Agent calls
block()orsubscribe()in application flow - keep subscription with the runtime. - Agent uses
ThreadLocalfor tenant or trace data - use ReactorContext. - Agent uses unbounded
flatMap- set concurrency from downstream limits. - Agent wraps JDBC with
Mono.just- this still blocks the event loop.