node-postgres/lib/pool.js
2013-03-07 10:01:14 -06:00

118 lines
3.8 KiB
JavaScript

var EventEmitter = require('events').EventEmitter;
var defaults = require(__dirname + '/defaults');
var genericPool = require('generic-pool');
var deprecate = require('deprecate');
var pools = {
//dictionary of all key:pool pairs
all: {},
//reference to the client constructor - can override in tests or for require('pg').native
Client: require(__dirname + '/client'),
getOrCreate: function(clientConfig) {
clientConfig = clientConfig || {};
var name = JSON.stringify(clientConfig);
var pool = pools.all[name];
if(pool) {
return pool;
}
pool = genericPool.Pool({
name: name,
max: defaults.poolSize,
idleTimeoutMillis: defaults.poolIdleTimeout,
reapIntervalMillis: defaults.reapIntervalMillis,
log: defaults.poolLog,
create: function(cb) {
var client = new pools.Client(clientConfig);
client.connect(function(err) {
if(err) return cb(err, null);
//handle connected client background errors by emitting event
//via the pg object and then removing errored client from the pool
client.on('error', function(e) {
pool.emit('error', e, client);
pool.destroy(client);
});
return cb(null, client);
});
},
destroy: function(client) {
client.end();
}
});
pools.all[name] = pool;
//mixin EventEmitter to pool
EventEmitter.call(pool);
for(var key in EventEmitter.prototype) {
if(EventEmitter.prototype.hasOwnProperty(key)) {
pool[key] = EventEmitter.prototype[key];
}
}
//monkey-patch with connect method
pool.connect = function(cb) {
pool.acquire(function(err, client) {
if(err) return cb(err, null, function() {/*NOOP*/});
//support both 2 (old) and 3 arguments
(cb.length > 2 ? newConnect : oldConnect)(pool, client, cb);
});
};
return pool;
}
};
//the old connect method of the pool
//would automatically subscribe to the 'drain'
//event and automatically return the client to
//the pool once 'drain' fired once. This caused
//a bunch of problems, but for backwards compatibility
//we're leaving it in
var alarmDuration = 5000;
var errorMessage = [
'A client has been checked out from the pool for longer than ' + alarmDuration + ' ms.',
'You might have a leak!',
'You should use the following new way to check out clients','pg.connect(function(err, client, done)) {',
' //do something',
' done(); //call done() to signal you are finished with the client',
'}'
].join(require('os').EOL);
var oldConnect = function(pool, client, cb) {
deprecate('pg.connect(function(err, client) { ...}) is deprecated and will be removed it v1.0.0 (very soon)',
'instead, use pg.connect(function(err, client, done) { ... })',
'automatic releasing of clients back to the pool was a mistake and will be removed',
'please see the following for more details:',
'https://github.com/brianc/node-postgres/wiki/pg',
'https://github.com/brianc/node-postgres/issues/227',
'https://github.com/brianc/node-postgres/pull/274',
'feel free to get in touch via github if you have questions');
var tid = setTimeout(function() {
console.error(errorMessage);
}, alarmDuration);
var onError = function() {
clearTimeout(tid);
client.removeListener('drain', release);
};
var release = function() {
clearTimeout(tid);
pool.release(client);
client.removeListener('error', onError);
};
client.once('drain', release);
client.once('error', onError);
cb(null, client);
};
var newConnect = function(pool, client, cb) {
cb(null, client, function(err) {
if(err) {
pool.destroy(client);
} else {
pool.release(client);
}
});
};
module.exports = pools;