2013-02-20 09:34:28 +08:00
|
|
|
var EventEmitter = require('events').EventEmitter;
|
|
|
|
|
2013-02-16 06:13:28 +08:00
|
|
|
var defaults = require(__dirname + '/defaults');
|
|
|
|
var genericPool = require('generic-pool');
|
|
|
|
|
2013-02-21 06:08:48 +08:00
|
|
|
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);
|
2013-02-20 09:34:28 +08:00
|
|
|
|
2013-02-21 06:08:48 +08:00
|
|
|
//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);
|
|
|
|
});
|
2013-02-20 09:34:28 +08:00
|
|
|
|
2013-02-21 06:08:48 +08:00
|
|
|
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];
|
|
|
|
}
|
2013-02-20 09:34:28 +08:00
|
|
|
}
|
2013-02-21 06:08:48 +08:00
|
|
|
//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;
|
2013-02-20 09:34:28 +08:00
|
|
|
}
|
|
|
|
};
|
2013-02-16 06:13:28 +08:00
|
|
|
|
|
|
|
//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
|
2013-02-20 09:34:28 +08:00
|
|
|
var alarmDuration = 5000;
|
2013-02-21 06:08:48 +08:00
|
|
|
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);
|
|
|
|
|
2013-02-16 06:13:28 +08:00
|
|
|
var oldConnect = function(pool, client, cb) {
|
|
|
|
var tid = setTimeout(function() {
|
|
|
|
console.error(errorMessage);
|
|
|
|
}, alarmDuration);
|
|
|
|
var release = function() {
|
|
|
|
clearTimeout(tid);
|
|
|
|
pool.release(client);
|
|
|
|
};
|
|
|
|
client.once('drain', release);
|
|
|
|
cb(null, client);
|
|
|
|
};
|
|
|
|
|
|
|
|
var newConnect = function(pool, client, cb) {
|
2013-02-20 09:34:28 +08:00
|
|
|
cb(null, client, function(err) {
|
|
|
|
if(err) {
|
|
|
|
pool.destroy(client);
|
|
|
|
} else {
|
|
|
|
pool.release(client);
|
|
|
|
}
|
2013-02-16 06:13:28 +08:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2013-02-21 06:08:48 +08:00
|
|
|
module.exports = pools;
|