You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring WebFlux接口异常:首次请求正常后续请求挂起问题排查

Why Your Spring WebFlux App Hangs After the First Request

Hey Justin, let's break down why your /route/accountInformation endpoint works once then gets stuck indefinitely. The root issue is a critical mistake in how you're handling reactive streams in your getAccountInformation() method:

String queryParams = "recvWindow=50000&timestamp=" + responseServerTime.block().getServerTime();

The Problem with block() in WebFlux

Spring WebFlux relies on a small pool of non-blocking threads to handle requests. When you call block(), you force that thread to pause and wait synchronously for the Mono<ResponseServerTime> to finish.

  • The first request uses up one of these limited threads, holding it hostage until the Binance time API responds.
  • Once all threads in the pool are stuck on blocking calls, there are no threads left to process new requests. That's exactly why subsequent calls hang forever.

Blocking operations completely break the reactive, non-blocking model WebFlux is built on—they're one of the biggest pitfalls for new reactive developers.

The Fix: Go Fully Reactive

We need to rewrite getAccountInformation() to use reactive operators instead of blocking. Here's the corrected version:

public Mono<AccountInformation> getAccountInformation() {
    return binanceServerTimeApi.getServerTime()
            // Process server time reactively once it's available
            .map(responseServerTime -> {
                String queryParams = "recvWindow=50000&timestamp=" + responseServerTime.getServerTime();
                String signature = HmacSHA256Signer.sign(queryParams, secret);
                return queryParams + "&signature=" + signature;
            })
            // Chain the account info request once we have the signed params
            .flatMap(signedQuery -> {
                // Use UriBuilder for safer, cleaner URL construction
                return this.webClient.get()
                        .uri(uriBuilder -> uriBuilder
                                .path("api/v3/account")
                                .query(signedQuery)
                                .build())
                        .accept(MediaType.APPLICATION_JSON)
                        .retrieve()
                        .bodyToMono(AccountInformation.class);
            })
            .log();
}

Key Improvements:

  1. Replace block() with map(): We process the server time asynchronously once it arrives, no thread blocking involved.
  2. Use flatMap() for WebClient calls: Since webClient.get() returns a Mono, flatMap() lets us chain it seamlessly to the previous reactive stream.
  3. Safer URL building: UriBuilder eliminates errors from manual string concatenation (like missing ? or invalid characters).

Quick Thread Safety Check

Double-check that HmacSHA256Signer.sign() is thread-safe. If it uses mutable state (like a non-thread-safe MessageDigest instance), it could cause weird bugs in a reactive environment. If it's not thread-safe, create a new instance per call or use a thread-local to handle it safely.

Why This Fix Works

Now the entire flow is non-blocking:

  • The server time request runs asynchronously, freeing the thread to handle other requests while waiting.
  • When the time comes back, we generate the signature and trigger the account info request without pausing any threads.
  • Threads are never stuck waiting, so your app can handle concurrent requests smoothly.

After making these changes, your endpoint should work reliably for every request, not just the first one.

内容的提问来源于stack exchange,提问作者Justin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:52:58