WebFlux Reactive Patterns
Use WebFlux when the complete request path can benefit from non-blocking I/O.
Pipeline rules
- Return
MonoorFlux; do not callsubscribe()in request-handling code. - Compose work with
map,flatMap,concatMap, andzipaccording to ordering requirements. - Keep blocking JDBC, filesystem, and legacy SDK calls out of event-loop threads.
- Isolate unavoidable blocking calls on
boundedElasticat the narrow adapter boundary. - Apply timeouts at remote-call boundaries and preserve cancellation.
Context and errors
- Put request-scoped metadata in Reactor
Context, notThreadLocal. - Translate domain failures centrally without swallowing cancellation or infrastructure errors.
- Use
onErrorResumeonly when a defined fallback exists. - Avoid
onErrorContinue; it makes partial processing hard to reason about.
Persistence and streaming
- Use R2DBC for reactive database access; JDBC makes the pipeline blocking.
- Bound concurrency for fan-out operations.
- Define backpressure and buffering limits for streaming endpoints.
- Avoid collecting an unbounded
Fluxinto memory.
Testing
- Use
StepVerifierfor publisher behavior andWebTestClientfor HTTP contracts. - Test cancellation, timeout, empty results, errors, ordering, and backpressure.
- Enable blocking-call detection in tests when the project supports it.
Examples
- See
examples/good-reactive-service.javaandexamples/bad-reactive-service.java.
Gotchas
- Agent calls
block()in a controller or service - keep the full request path non-blocking. - Agent calls
subscribe()manually - the web runtime owns subscription. - Agent stores tenant or security data in
ThreadLocal- use ReactorContext. - Agent uses unbounded
flatMap- set concurrency according to downstream capacity. - Agent wraps JDBC in
Mono.just- that still blocks the caller thread.