Barry Steyn
Barry Steyn

Reputation: 1603

Asynchronous calls using postgres as an example in NodeJS

When implementing this code (example taken directly from https://github.com/brianc/node-postgres):

var pg = require('pg'); 

var conString = "tcp://postgres:1234@localhost/postgres";

pg.connect(conString, function(err, client) {
  client.query("SELECT NOW() as when", function(err, result) {
      console.log("Row count: %d",result.rows.length);  // 1
      console.log("Current year: %d", result.rows[0].when.getFullYear());
      //Code halts here
  });
});

After the last console.log, node hangs. I think this is because the asynchronous nature, and I suspect at this point, one should call a callback function.

I have two questions:

  1. Is my thinking correct?
  2. If my thinking is correct, then how does the mechanics work. I know NodeJS is using an event loop, but what is making this event loop halt at this point?

Upvotes: 3

Views: 2562

Answers (1)

Jonathan Lonowski
Jonathan Lonowski

Reputation: 123433

It appears to hang because the connection to Postgres is still open. Until it's closed, or "ended"...

client.end(); // Code halts here

Node will continue to wait in idle for another event to be added to the queue.


  1. Not quite. This is a detail of node-postgres and its dependencies, not of Node or of its "asynchronous nature" in general.

  2. The idling is due to and documented for the generic-pool module that node-postgres uses:

    If you are shutting down a long-lived process, you may notice that node fails to exit for 30 seconds or so. This is a side effect of the idleTimeoutMillis behavior -- the pool has a setTimeout() call registered that is in the event loop queue, so node won't terminate until all resources have timed out, and the pool stops trying to manage them.

    And, as it explains under Draining:

    If you know would like to terminate all the resources in your pool before their timeouts have been reached, you can use destroyAllNow() in conjunction with drain():

    pool.drain(function() {
        pool.destroyAllNow();
    });
    

    One side-effect of calling drain() is that subsequent calls to acquire() will throw an Error.

    Which is what pg.end() does and can certainly be done if your intention is to exit at the end of a serial application, such as unit testing or your given snippet.

Upvotes: 6

Related Questions