Skip to content

Commit 70d86bb

Browse files
authored
Merge pull request #1791 from qingyang-id/release-idle-connection
Release idle connection
2 parents ba15fe2 + 1cabf65 commit 70d86bb

File tree

9 files changed

+101
-2
lines changed

9 files changed

+101
-2
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ const pool = mysql.createPool({
132132
database: 'test',
133133
waitForConnections: true,
134134
connectionLimit: 10,
135+
maxIdle: 10, // max idle connections, the default value is the same as `connectionLimit`
136+
idleTimeout: 60000, // idle connections timeout, in milliseconds, the default value 60000
135137
queueLimit: 0
136138
});
137139
```

index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ export interface ConnectionOptions extends mysql.ConnectionOptions {
180180
stream?: any;
181181
uri?: string;
182182
connectionLimit?: number;
183+
maxIdle?: number;
184+
idleTimeout?: number;
183185
Promise?: any;
184186
queueLimit?: number;
185187
waitForConnections?: boolean;

lib/connection_config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ const validOptions = {
5959
user: 1,
6060
// These options are used for Pool
6161
connectionLimit: 1,
62+
maxIdle: 1,
63+
idleTimeout: 1,
6264
Promise: 1,
6365
queueLimit: 1,
6466
waitForConnections: 1

lib/pool.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ class Pool extends EventEmitter {
2727
this._freeConnections = new Queue();
2828
this._connectionQueue = new Queue();
2929
this._closed = false;
30+
if (this.config.maxIdle < this.config.connectionLimit) {
31+
// create idle connection timeout automatically release job
32+
this._removeIdleTimeoutConnections();
33+
}
3034
}
3135

3236
promise(promiseImpl) {
@@ -40,7 +44,7 @@ class Pool extends EventEmitter {
4044
}
4145
let connection;
4246
if (this._freeConnections.length > 0) {
43-
connection = this._freeConnections.shift();
47+
connection = this._freeConnections.pop();
4448
this.emit('acquire', connection);
4549
return process.nextTick(() => cb(null, connection));
4650
}
@@ -187,6 +191,26 @@ class Pool extends EventEmitter {
187191
this.releaseConnection(connection);
188192
}
189193

194+
_removeIdleTimeoutConnections() {
195+
if (this._removeIdleTimeoutConnectionsTimer) {
196+
clearTimeout(this._removeIdleTimeoutConnectionsTimer);
197+
}
198+
199+
this._removeIdleTimeoutConnectionsTimer = setTimeout(() => {
200+
try {
201+
while (
202+
this._freeConnections.length > this.config.maxIdle &&
203+
Date.now() - this._freeConnections.get(0).lastActiveTime >
204+
this.config.idleTimeout
205+
) {
206+
this._freeConnections.get(0).destroy();
207+
}
208+
} finally {
209+
this._removeIdleTimeoutConnections();
210+
}
211+
}, 1000);
212+
}
213+
190214
format(sql, values) {
191215
return mysql.format(
192216
sql,

lib/pool_config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ class PoolConfig {
1515
this.connectionLimit = isNaN(options.connectionLimit)
1616
? 10
1717
: Number(options.connectionLimit);
18+
this.maxIdle = isNaN(options.maxIdle)
19+
? this.connectionLimit
20+
: Number(options.maxIdle);
21+
this.idleTimeout = isNaN(options.idleTimeout)
22+
? 60000
23+
: Number(options.idleTimeout);
1824
this.queueLimit = isNaN(options.queueLimit)
1925
? 0
2026
: Number(options.queueLimit);

lib/pool_connection.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ class PoolConnection extends Connection {
66
constructor(pool, options) {
77
super(options);
88
this._pool = pool;
9+
// The last active time of this connection
10+
this.lastActiveTime = Date.now();
911
// When a fatal error occurs the connection's protocol ends, which will cause
1012
// the connection to end as well, thus we only need to watch for the end event
1113
// and we will be notified of disconnects.
@@ -22,6 +24,8 @@ class PoolConnection extends Connection {
2224
if (!this._pool || this._pool._closed) {
2325
return;
2426
}
27+
// update last active time
28+
this.lastActiveTime = Date.now();
2529
this._pool.releaseConnection(this);
2630
}
2731

test/common.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,10 @@ exports.getConfig = function(input) {
105105
timezone: args && args.timezone,
106106
dateStrings: args && args.dateStrings,
107107
authSwitchHandler: args && args.authSwitchHandler,
108-
typeCast: args && args.typeCast
108+
typeCast: args && args.typeCast,
109+
connectionLimit: args && args.connectionLimit,
110+
maxIdle: args && args.maxIdle,
111+
idleTimeout: args && args.idleTimeout,
109112
};
110113
return params;
111114
};
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use strict';
2+
3+
const createPool = require('../common.js').createPool;
4+
const assert = require('assert');
5+
6+
const pool = new createPool({
7+
connectionLimit: 5, // 5 connections
8+
maxIdle: 1, // 1 idle connection
9+
idleTimeout: 5000, // 5 seconds
10+
});
11+
12+
pool.getConnection((err1, connection1) => {
13+
assert.ifError(err1);
14+
assert.ok(connection1);
15+
pool.getConnection((err2, connection2) => {
16+
assert.ifError(err2);
17+
assert.ok(connection2);
18+
assert.notStrictEqual(connection1, connection2);
19+
pool.getConnection((err3, connection3) => {
20+
assert.ifError(err3);
21+
assert.ok(connection3);
22+
assert.notStrictEqual(connection1, connection3);
23+
assert.notStrictEqual(connection2, connection3);
24+
connection1.release();
25+
connection2.release();
26+
connection3.release();
27+
assert(pool._allConnections.length === 3);
28+
assert(pool._freeConnections.length === 3);
29+
setTimeout(() => {
30+
assert(pool._allConnections.length === 1);
31+
assert(pool._freeConnections.length === 1);
32+
pool.getConnection((err4, connection4) => {
33+
assert.ifError(err4);
34+
assert.ok(connection4);
35+
assert.strictEqual(connection3, connection4);
36+
assert(pool._allConnections.length === 1);
37+
assert(pool._freeConnections.length === 0);
38+
connection4.release();
39+
connection4.destroy();
40+
pool.end();
41+
setTimeout(() => process.exit(0), 1000);
42+
});
43+
}, 7000);
44+
});
45+
});
46+
});

typings/mysql/lib/Pool.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ declare namespace Pool {
2626
*/
2727
connectionLimit?: number;
2828

29+
/**
30+
* The minimum number of idle connections. (Default: 10)
31+
*/
32+
maxIdle?: number;
33+
34+
/**
35+
* The idle connections timeout, in milliseconds. (Default: 60000)
36+
*/
37+
idleTimeout?: number;
38+
2939
/**
3040
* The maximum number of connection requests the pool will queue before returning an error from getConnection. If set to 0, there
3141
* is no limit to the number of queued connection requests. (Default: 0)

0 commit comments

Comments
 (0)