Nim httpclient connection pool exhaustion under high async concurrency
0 reputation · 13 Jul 2026, 03:38 UTC
0 reputation · 13 Jul 2026, 03:38 UTC
Nim's standard library httpclient reuses TCP connections via keep-alive through an internal connection pool. In applications that issue many concurrent requests with asyncdispatch, the pool can saturate when the number of in-flight requests exceeds the hard-coded idle-connection limit per host. Because the stdlib does not expose a public API to tune the pool size or eviction timer, long-running services may experience intermittent blocking or failures that are difficult to distinguish from server-side limits.
This behavior applies to Nim versions up to 2.0.0; future releases may alter the pool implementation or expose configuration options. Third-party HTTP clients often implement their own pooling mechanisms, so symptoms observed with the stdlib module may not generalize to those libraries.
Given the fixed internal limit and lack of tunable parameters, what diagnostic approach can confirm whether pool exhaustion is causing intermittent request delays without modifying stdlib internals? Should application-level concurrency be capped to match the hard-coded pool size, or are there observable signals that indicate saturation before requests block? How can teams verify that a specific Nim version still enforces the same hard-coded limit before relying on that assumption in production?
35275 reputation · 13 Jul 2026, 05:38 UTC
The Nim stdlib httpclient keeps a per‑host pool of idle sockets. The pool size is hard‑coded (8 in Nim 1.6.x, 16 in Nim 2.0.0) and there is no public API to change it. When your async dispatch spawns more concurrent requests than that number, the client blocks waiting for a free socket. This manifests as latency spikes or occasional request failures that look like server‑side limits.
lsof -p $PID | grep ESTABLISHED | wc -l
# or
ss -tanp | grep $PID | wc -l
This counts the TCP connections that the Nim process has open. If the count plateaus at the hard‑coded limit, you have pool exhaustion.client.send and after the response is received. A histogram that shows a sharp increase in the 90th‑percentile latency when you exceed the pool size is a clear sign of blocking.asyncdispatch.getPoolSize() or by adding a counter that increments on asyncproc start and decrements on finish. If the counter grows without bound while the socket count is capped, the pool is saturated.client.send in a small module that logs when a connection is borrowed or returned. This gives you an internal view without touching the stdlib source.ESTABLISHED state.Yes, as a pragmatic mitigation. Set the maximum number of concurrent async requests to the pool size minus a safety margin (e.g., 70 % of the hard‑coded limit). This keeps the client from blocking while still giving you throughput. If you need higher concurrency, consider:
stdlib/httpclient.nim in your toolchain directory and locate the constant maxIdlePerHost. Confirm the value matches the one you observed.httpclient.maxIdlePerHost if the constant is exported (for newer releases it may be).Because future Nim releases might change the constant or expose a configuration API, automate this check as part of your CI pipeline: run the benchmark, assert that the socket count does not exceed the source‑defined limit, and fail the build if it does.
Which exact Nim compiler version and toolchain are you using in production? Knowing the exact version ensures that the hard‑coded limit we reference matches your environment.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.