Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knex: Timeout acquiring a connection

Since today, I get the following error when I try to locally connect to a postgres database (v 12) using knex.js.

Unhandled rejection TimeoutError: Knex: Timeout acquiring a connection. The pool is probably full. Are you missing a .transacting(trx) call?

This happens on a project I've been working on for a year without any problems. Trying to isolate the issue, I created a new database with one table. When running the following lines of code, I get the same error:

const knex = require('knex');

const db = knex({
  client: 'pg',
  connection: 'postgresql://postgres:postgres@localhost/a_test',
  pool: {
    min: 0,
    max: 10,
  },
});

db.from('test_table')
  .select(['id'])
  .then(r => {
    console.log(r);
  });

I have no clue what might cause this. A couple of weeks ago everything worked fine and I didn't change anything in the meantime. I run postgres locally with postgresapp and when I connect to the database using psql, everything works fine. Any ideas where I could look to resolve this?

like image 805
Flavio Avatar asked Dec 07 '22 10:12

Flavio


1 Answers

The problem

Nodejs V14 Made some breaking changes that affected the pg module! Which made it exit directly at connect() call.

One can know by downgrading to v13! (I call it the v14 HELL)! Which was a solution in the past!

A fix for pg was written in pg v8.0.3.

Fix for v14

If you are using postgres! With nodejs v14 and above ! Make sure to use the driver module pg at version >=8.0.3! And better upgrade to the latest

npm install pg@latest --save

If you are not using postgres! Try to update your DB driver! It may be the same! Also try with nodejs V13. To confirm it's the same problem! (V14 HELL)

What did happen in v14

If like me you like to know the details and what did happen !?

With node V14! Some breaking changes happened on the api! Also many things were changed! Including Openssl version!

For postgres! And pg module! The problem was as described in this comment per this thread:

The initial readyState (a private/undocumented API that

pg uses) of net.Socket seems to have changed from 'closed' to 'open' in Node 14.

It’s hard to fix with perfect backwards compatibility, but I think I have a patch that’s close enough.

And as per this PR!

You can see the changes in this diffing

In short as mentioned! The api for onReady changed for a net.Socket ! And the implemented solution was to not use onReady at all!

And as per this

Connection now always calls connect on its stream when connect is called on it.

In the older version the connect was called only if the socket is on closed state! readyState usage is eliminated!

Check this line

You can understand!

Depending on the implementation! Many things may or not be affected by those core changes!

Nodejs v14 relevant change

And because i wanted to see where the change happen! Here you go

https://github.com/nodejs/node/pull/32272

One can check the log of changes too:

https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V14.md

Detailed Why + exit and no logging error

Also to mention the breaking changes! Made pg make the process exit at connect() call. And that's what made it exit! And logging was to be seen! In more detail for this! Here how it happened! Sequelize have the postgres dialect implementation! Which use pg! And pg client! create a connection! The connection have a connect event! When it connect it emit it! And because node v14 change the behavior of a stream to starting with open! The stream connection is skipped! Because of the readyState check (expected as close but it became open instead!)! And the stream is taken as connected (else block)! Where it is not! And the connect event is emitted directly! When that happen! The client either will call requestSsl() or startup() method of the connection object! And both will call this._stream.write. because the stream is not connected! An error happen! This error is not catch! Then the promise in sequelize driver! Will stay unresolved! And then the event loop get empty! Nodejs by default behavior just exit!

You can see the step through lines of code:

  • Sequelize pg adapter will call pg client to create a connection and the promise
  • pg client call connect on a connection object
  • pg connection connect() call and emit connect! Thinking the stream is connected because of V14 change
  • pg client connect event catched and callback run! requestSsl() or startup() will be run
  • One of the method get run and stream.write will be called (requestSsl(), startup())
  • Stream Error (not catched)
  • Promise in sequelize postgres adapter! Still unresolved!
  • event loop empty => Nodejs => Exit

Why nodejs exit (unresolved promises)

https://github.com/nodejs/node/issues/22088

Node exits without error and doesn't await promise (Event callback)

what happens when a Promise never resolves?

like image 184
Mohamed Allal Avatar answered Dec 11 '22 08:12

Mohamed Allal