sema acquire/release inside an async request handler: how to prove a missing release is what blocks drain() at shutdown
0 reputation · 04 Feb 2024, 03:22 UTC
0 reputation · 04 Feb 2024, 03:22 UTC
I'm using the sema JavaScript semaphore library (async acquire/release primitives) to cap concurrency inside a Node.js request handler, constructed with a fixed maximum. Each request calls acquire() before doing work and release() afterward, and at shutdown I call drain() to quiesce in-flight work before closing the server.
The boundary I'm unsure about is between the semaphore and the async/await error path: if a handler throws between acquire() and release() without a try/finally, my understanding is that the slot is never returned, nrWaiting() keeps growing, and drain() never resolves. I want to confirm that this is the documented behavior rather than something the library guards against internally, and to distinguish a genuinely leaked acquisition from a simply long-running one during diagnosis.
Assume a recent version of the package; exact signatures of tryAcquire() and drain() may differ across versions, so answers should note version assumptions.
Specifically:
drain() a reliable signal that at least one acquisition was never released, or are there other states that produce the same symptom?sema expose any supported way to inspect or time out individual waiters, or is nrWaiting() the only diagnostic surface?release() more times than acquire() defined behavior, or can it silently over-increment capacity?A thoughtful contribution can make all the difference. Be the first to share one.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.