ADR-0010: Jolokia calls over a blocking RestClient; spring-boot-starter-webflux removed
- Status: accepted
- Date: 2026-09-03
- Deciders: Mahdi Amirabdollahi
Context
ADR-0002 makes Jolokia HTTP the primary broker channel. The workspace scaffold carries spring-boot-starter-webflux with a pom.xml comment — "WebClient for Jolokia HTTP calls; SSE via Flux<ServerSentEvent>" — recording an intent, not a decision. Phase 1 writes the first real client, so the intent has to become a decision.
Facts on the ground: spring.threads.virtual.enabled is already true. The Jolokia call pattern is one batched POST per node per scrape tier — request / response, low fan-out, no streaming. Nothing in Phase 1 or Phase 2's scope needs back-pressure or reactive composition. ADR-0003 puts real-time on SSE, and Spring MVC serves SSE with SseEmitter without WebFlux.
The global engineering rules: "Do not preserve backward compatibility. Remove obsolete paths instead of adding compatibility layers, fallbacks, or migrations," and prefer the simplest thing that meets the current requirement.
Decision
- The Jolokia client is a blocking
RestClient(Spring's synchronous HTTP client, already provided byspring-boot-starter-web), running on virtual threads. ABrokerClientFactorybuilds oneRestClientper cluster: per-node base URL, HTTP Basic from theSecretVault, anSslBundles-derived request factory for TLS brokers, connect timeout 3s, read timeout 10s. spring-boot-starter-webfluxis removed frompom.xml. Nothing imports it; keeping an unused parallel web stack is the obsolete path the rules forbid.- SSE (Phase 2) uses
SseEmitteron Spring MVC. If a future feature has a genuine reactive requirement, WebFlux returns as its own dependency with its own ADR.
This supersedes the pom.xml "WebClient for Jolokia" comment.
Consequences
- One HTTP programming model in the codebase; reactive types never enter
broker/,domain/, or the Phase 2 scheduler. - Smaller dependency graph and container image; fewer auto-configurations at boot.
- Blocking I/O is cheap here because it runs on virtual threads and the call count per scrape is bounded by node count, not queue count (ADR-0002 non-negotiable #1).
- A later reactive need pays the cost of re-adding and wiring WebFlux at that point — judged unlikely and cleanly reversible.
Alternatives considered
- Keep WebFlux, use
WebClientblocking (.block()). DragsMono/Fluxand a second web stack in for a synchronous call pattern;.block()on the reactive scheduler is an anti-pattern. Rejected. java.net.http.HttpClientdirectly. Works, but loses Spring's message converters,MockRestServiceServertest support, and SSL-bundle integration thatRestClientgets for free. Rejected.- Keep the dependency "just in case." The explicit target of the "no obsolete paths" rule. Rejected.