Knex: timeout acquiring a connection, the pool is probably full
May 5, 2024
May 5, 2024
Error: Knex: Timeout acquiring a connection. The pool is probably full. Are you missing a .transacting(trx) call?
Yes, youâre probably missing a .transacting(trx)
call, but whatâs
going on exactly?
Knex maintains a connection pool to your database, which you configure
with the pool
min
and max
options.
If max
is 5, then Knex will keep up to 5 connections to your database
in the pool.
If youâre attempting to make a query and the pool is full, then itâll wait that one of the connection frees up in order to use it.
Sometimes however, it will timeout doing so. One common case is a deadlock when mixing queries inside and outside a transaction.
Letâs say that you start 5 transactions, but within those transactions, youâre performing some queries outside of the transaction:
await knex.transaction(trx => {
await trx.raw('...')
await knex.raw('...')
})
Here, the knex.raw
statement will execute outside of the transaction
(despite being in the function, because it doesnât use trx
). This
means that it will use its own connection from the pool, on top of the
one knex.transaction
already uses.
If you have enough of those running in parallel, you can hit a case
where thereâs no available connection to execute the knex.raw
bit. So
itâs waiting that a connection frees up. But no connection get freed up
because all the transactions are waiting for the knex.raw
bit to
complete in order to commit!
See the deadlock here?
So the solution is to make sure that all the queries you perform inside
the transaction actually use that transaction. In the above example,
itâs very obvious, but it can get trickier when you call a function that
calls another function that calls a method that makes a query but didnât
accept a trx
parameter and so ends up needing its own connection. đŹ
Now you know what to look for. đ