An HTTP service interface backed by WebClient starts remote work on subscription and inherits cancellation and timeout behavior.
Reactive HTTP service client: the proxy returns a publisher, not a completed call
Subscription owns the attempt
A method returning Mono<PriceQuote> can describe a remote request without sending it yet. If two callers subscribe independently to a cold result, two HTTP attempts may occur. If the downstream commits a write, repeating subscription has the same uncertainty as a retry. Keep a stable command ID for writes and avoid hidden subscribe calls inside handlers.
Cancellation is not a remote rollback
A browser disconnect or timeout can cancel the local publisher after the request reached the remote service. The remote side may still complete. For read-only calls, cancellation mainly affects resource use and latency. For a write, reconcile by command ID or query a durable result. Reactive transactions protect local database work in their chain; they cannot roll back a separate HTTP service.
Make the boundary testable
Back the interface with a WebClient adapter, then test against a stub that delays a response and records received requests. Subscribe twice and count attempts; cancel after the server receives a POST and verify the application reports uncertainty rather than false failure. The code creates a proxy but does not supply production timeouts or authentication.
Implementation sketch
@HttpExchange("/v1/prices")
interface ReactivePricingClient {
@GetExchange("/{sku}")
Mono<PriceQuote> quote(@PathVariable String sku);
}
var adapter = WebClientAdapter.create(webClient);
var client = HttpServiceProxyFactory.builderFor(adapter).build()
.createClient(ReactivePricingClient.class);Cost and verification
Non-blocking I/O can support many pending calls with fewer request threads, but each active call still consumes a connection and buffers. Timeouts and concurrency limits remain necessary.
Common Mistakes
- Do not call subscribe inside a controller and return before the remote result is known.
- Do not assume cancellation undoes a remote write.
- Do not reuse a cold publisher as though it were a cached result.
Read next
Spring HTTP service client: the interface is a contract, not a transport policy, Spring HTTP service client retries: an interface cannot prove the server did not commit, Spring WebClient exchangeToMono: decode the response inside its callback, Spring reactive transaction: subscription owns the context, not a thread.
