Knex 3.x pool configuration: idle connection eviction versus database-side TCP timeouts
0 reputation · 15 Apr 2025, 09:17 UTC
0 reputation · 15 Apr 2025, 09:17 UTC
I am configuring the Knex.js connection pool (backed by tarn.js) for a service where the database server drops idle TCP connections aggressively. The goal is to ensure that a connection handed out from the pool is never one the server has already closed, without over-evicting healthy idle connections.
Knex exposes pool.min, pool.max, idleTimeoutMillis, reapIntervalMillis, and acquireTimeoutMillis, plus hooks such as afterCreate. My understanding is that Knex itself has no query result cache, so any "stale" behavior here is about dead pooled connections, not cached data. What is unclear is the interaction ordering: if the database wait_timeout is shorter than idleTimeoutMillis, a pooled connection can be silently dead before tarn.js ever reaps it, and I am unsure which documented mechanism is intended to catch that case.
Assume Knex 3.x with a recent tarn.js; exact option names and defaults should be verified against the installed versions.
idleTimeoutMillis always be set below the database wait_timeout, or is a validation/afterCreate hook the documented way to evict dead connections?pool.min above zero increase the risk of handing out silently killed connections behind short firewall TCP timeouts?32275 reputation · 15 Apr 2025, 14:29 UTC
There is no validation query in Knex 3.x that checks a connection before it is handed out. The intended defense against a database that closes idle TCP connections is pool-side eviction: set pool.idleTimeoutMillis comfortably below the server's wait_timeout (and below any firewall idle timeout), and make sure reapIntervalMillis runs often enough to actually enforce it. afterCreate runs once when a connection is created — it is not a recurring health check and cannot catch a connection that died while idle in the pool.
Knex delegates pooling to tarn.js, and tarn.js has no built-in "test on borrow" query. So the documented mechanism is eviction, not validation. The ordering that matters:
wait_timeout < idleTimeoutMillis, the server closes the socket first and the pool hands out a dead connection. Your query then fails with something like Connection lost / socket hang-up.idleTimeoutMillis < wait_timeout, tarn destroys the connection while it is still healthy, and the next acquire creates a fresh one.Leave headroom for the reaper: tarn only checks idleness every reapIntervalMillis, so effective eviction can lag the configured idle timeout by up to one interval. A practical rule: idleTimeoutMillis + reapIntervalMillis < wait_timeout. Example for MySQL's default 8-hour timeout, or a stricter 60-second proxy/firewall timeout:
pool: {
min: 0,
max: 10,
idleTimeoutMillis: 30000, // well under a 60s network/db timeout
reapIntervalMillis: 1000, // check for idle connections every second
acquireTimeoutMillis: 10000
}The trade-off: very low idle timeouts cause connection churn (repeated TCP handshakes and auth). Don't go lower than your typical gap between queries.
Yes, indirectly. With min: 0, an idle pool drains to zero and every acquire after a quiet period creates a brand-new connection. With min: 2, those two connections sit idle indefinitely and are exactly the ones a firewall or wait_timeout will silently kill — and idle-timeout eviction is the only thing that removes them. If your environment has short network idle timeouts, prefer min: 0, or keep idleTimeoutMillis below the shortest timeout in the path (load balancer, NAT, firewall, and the DB itself).
SHOW VARIABLES LIKE 'wait_timeout'; (MySQL) or SHOW idle_in_transaction_session_timeout; / TCP keepalive settings (Postgres). Compare against your pool settings.DEBUG=knex:* (or at least knex:query, knex:client) to watch acquire/release timing.SET GLOBAL wait_timeout = 10;), let a pooled connection sit idle for 15 seconds, then issue a query. If eviction is configured correctly, the connection is reaped first and the query succeeds on a fresh connection; if not, you'll see a connection-lost error on first use.Option names and defaults above reflect Knex 3.x / recent tarn.js; verify against your installed versions (npm ls tarn). If you cannot tolerate a first-query failure even rarely, add application-level retry on connection errors, since Knex alone offers no pre-borrow validation.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.