diff --git a/Readme.md b/Readme.md index 3fd0209bc..064e50a27 100644 --- a/Readme.md +++ b/Readme.md @@ -247,6 +247,40 @@ cannot be re-connected by design. This logic will also be part of connection pool support once I add that to this library. +## Idle connections + +Connections emit `'drain'` events after they have finished all queued queries +(including query callbacks). This event could be used to detect idle +connections: + +```javascript +function detectIdle(connection) { + connection._idleTimeout = null; + + function clearIdleTimeout() { + if (connection.idleTimeout) { + clearTimeout(connection.idleTimeout); + } + } + + connection.on('drain', function() { + clearIdleTimeout(); + connection._idleTimeout = setTimeout(60000, function() { + console.error("Connection was idle for 60 seconds"); + // or return to a pool, etc. + }) + }) + + var query = connection.query; + connection.query = function() { + clearIdleTimeout(); + query.apply(connection, arguments); + }; +}) + +handleDisconnect(connection); +``` + ## Escaping query values In order to avoid SQL Injection attacks, you should always escape any user diff --git a/lib/Connection.js b/lib/Connection.js index d660882a3..416f5aeb6 100644 --- a/lib/Connection.js +++ b/lib/Connection.js @@ -30,6 +30,7 @@ Connection.prototype.connect = function(cb) { this._socket.on('error', this._handleNetworkError.bind(this)); this._protocol.on('unhandledError', this._handleProtocolError.bind(this)); + this._protocol.on('drain', this._handleProtocolDrain.bind(this)); this._protocol.on('close', this._handleProtocolClose.bind(this)); } @@ -126,6 +127,10 @@ Connection.prototype._handleProtocolError = function(err) { this.emit('error', err); }; +Connection.prototype._handleProtocolDrain = function(err) { + this.emit('drain', err); +}; + Connection.prototype._handleProtocolClose = function(err) { this.emit('close', err); }; diff --git a/lib/protocol/Protocol.js b/lib/protocol/Protocol.js index 054f86808..10d2a3a9f 100644 --- a/lib/protocol/Protocol.js +++ b/lib/protocol/Protocol.js @@ -195,6 +195,7 @@ Protocol.prototype._dequeue = function() { var sequence = this._queue[0]; if (!sequence) { + this.emit('drain') return; } diff --git a/test/integration/connection/test-drain-events.js b/test/integration/connection/test-drain-events.js new file mode 100644 index 000000000..ba5d23d6a --- /dev/null +++ b/test/integration/connection/test-drain-events.js @@ -0,0 +1,22 @@ +var common = require('../../common'); +var connection = common.createConnection(); +var assert = require('assert'); + +connection.connect(); + +var gotDrain = false; + +connection.on('drain', function() { + gotDrain = true; +}); + +connection.query("SELECT 1", function(err) { + // drain is not emitted until after the callback completes + assert.equal(gotDrain, false); + assert.ok(!err); + process.nextTick(function() { + assert.equal(gotDrain, true); + connection.end() + }) +}) +