question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

The connection pool sucks

See original GitHub issue

Hello -

I think the client object interface is pretty good. What is not a good interface is the current incarnation of the pool. Namely pg.connect. Here are some reasons why:

First of all, as a quick aside. The pooling was added to the module before the there was a lot of wisdom around “tiny modules that just do one thing.” Sooo really it would be better to have the pool in a completely separate module. I would like, probably, to start developing the pool off in it’s own module and maybe eventually rip the built in stuff out…but I don’t like breaking APIs. Anyways…

I think a good API makes the right thing easy and the wrong thing hard. Currently the pool is just about opposite of that.

Here are some examples of the pool sucking:

dead clients

Because the pool waits for a client’s query queue to drain, and once the client query queue is drained the client is automatically returned, if you never send a query to the client, the client is never returned. Eventually your pool is all checked out and idle and your app hangs. Here is an example of this total bullshit.

app.get('/', function(req, res, next) {
  pg.connect(app.constring, function(err, client) {
    if(!req.session) {
      return next();
      //way to go partner. you just leaked a connection
    }
    client.query('SELECT * FROM customers WHERE id = $1', [req.session.id], function(err, result) {
      var html = app.render('home', {user: JSON.stringify(result.rows[0])});
      res.send(html);
    })
  });
});

transactions

On the flip side of dead connections, greedy pool release mechanics of ‘the first drain event’ cause the client to get pushed back into the pool of available clients way too early.

pg.connect(/*constring*/, function(err, con) {
  con.query('begin', function(err) { //start our transaction
    con.query('update bla', function(err) {
      setTimeout(function() {
        //way to go partner, you returned this connection to the pool with an open transaction
        //better hope no one else wants to run a query for 2 seconds or some weird stuff is gonna happen
        con.query('commit');
      }, 2000);
    });
  });
});

That right there is an example of the ‘auto release’ being too greedy and not greedy enough.

I am going to fix this

I’d like to open up discussion around a different API for the pool. After 24/48 hours I’ll get started on a new implementation. So here’s what I’m thinking…this would be backwards compatible by adding a 3rd parameter to the pg.connect function. A callback you call when you want to release the client back to the pool. The callback itself will take a single error argument in the style of node. If the argument is non-null, the client will be closed and removed from the pool instead of returned to the pool. This is how it would look:

pg.connect(/*constring*/, function(err, client, done) {
   //hmmm....turns out I actually don't need this client
  done();
});

or what about doing a transaction? currently you have to do some nasy stuff with pauseDrain() and resumeDrain() which are themselves somewhat cludgey hacks I put on because I was mentally exhausted and planning a home remodel + my wedding. Well, I’m back now, refreshed, and want to make things better and all of our lives easier…

pg.connect(/*constring*/, function(err, client, done) {
  client.query('begin', function(err) {
    if(err) return callback();
    client.query('update something', function(err) {
      client.query('commit', function() { done() });
    })
  });
});

Also, the 1st parameter (connection info) is optional. I think node-postgres should use the same environment variables as the psql command to get default connection info, and then supplement with pg.defaults and then override with custom stuff passed in. So if you use defaults or the environment variables, you can do this:

pg.connect(function(client, done() {
  done();
});

The pool needs a cleaner way to shut itself down too without being destructive. I’m not sure how that should work currently.

feedback

I needs your feedback on this. Let’s hear it!

Issue Analytics

  • State:closed
  • Created 11 years ago
  • Reactions:1
  • Comments:37 (16 by maintainers)

github_iconTop GitHub Comments

1reaction
grncdrcommented, Jan 30, 2013

@vanuan use any-db, and ConnectionPool.query. Like so:

var pool = require('any-db').createPool('postgres://user:pass@localhost/databasename', {min: 2, max: 10})

// make a query
pool.query("SELECT * FROM users WHERE id = $1", [userId], function (err, res) {
  // do something with results.
})

This will never use more than 10 simultaneous connections, and you don’t have to worry about freeing them.

This is the correct approach 99% of the time, the only exception is if you need to perform multiple queries in a single transaction, in which case you need to hang on to a single connection for the duration of the transaction, which is what ConnectionPool.begin and Transaction objects are for.

pool.begin(function (tx) {
  tx.query(...)
  tx.query(...)
  tx.commit(function (err) {
    // if err == null then the transaction committed successfully
  })
})

There’s more detailed API descriptions for all of the any-db interfaces (they’re the same as what pq exposes) at the above links. If you run into stuff you don’t understand open issues requesting clarification on any-db.

0reactions
sjadhav-rpxcommented, Sep 3, 2017

.

Read more comments on GitHub >

github_iconTop Results From Across the Web

ELI5: Connection Pooling : r/learnprogramming - Reddit
A connection pool. ... With connection pooling, all five phones are always connected to Acme, so all your workers have to ... why...
Read more >
Scalable PostgreSQL Connection Pooler - Hacker News
It sucks to have to add complexity to your stack to fix a "deficiency" in ... Leading to most setups using 1:1 connection...
Read more >
Hibernate not releasing connections from connection pool
When you execute a query Hibernate will use a connection from the pool and then return it when it is done. It will...
Read more >
RE: To many connection problem with Postgresql - Forums
The pool will create additional connections when a connection is required but not available. You can control the connection pooling through portal-ext.
Read more >
How poolSize can impact MongoDB-backed Apps - Medium
1 What is connection pool and why do we need it? In software engineering, a connection pool is a cache of database connections...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found