Skip to content

Commit b091cf4

Browse files
fix: update connection cleanup process to handle expired connections and exceeding config.maxIdle (#3022)
* Updated connection cleanup process to ensure we cleanup connections that have expired as well as the connections that exceed the config.maxIdle setting * Added test case to ensure connections that have expired are removed, even when below maxIdle * Added test case to cover future regressions of this change * Ensure connection pool is closed to ensure the test completes without open handles --------- Co-authored-by: robertpitt <[email protected]>
1 parent 3298e50 commit b091cf4

File tree

4 files changed

+124
-4
lines changed

4 files changed

+124
-4
lines changed

lib/pool.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,10 @@ class Pool extends EventEmitter {
200200
this._removeIdleTimeoutConnectionsTimer = setTimeout(() => {
201201
try {
202202
while (
203-
this._freeConnections.length > this.config.maxIdle &&
204-
Date.now() - this._freeConnections.get(0).lastActiveTime >
205-
this.config.idleTimeout
203+
this._freeConnections.length > this.config.maxIdle ||
204+
(this._freeConnections.length > 0 &&
205+
Date.now() - this._freeConnections.get(0).lastActiveTime >
206+
this.config.idleTimeout)
206207
) {
207208
this._freeConnections.get(0).destroy();
208209
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'use strict';
2+
const createPool = require('../common.test.cjs').createPool;
3+
const { assert } = require('poku');
4+
5+
/**
6+
* This test case tests the scenario where released connections are not
7+
* being destroyed after the idle timeout has passed, to do this we setup
8+
* a pool with a connection limit of 3, and a max idle of 2, and an idle
9+
* timeout of 1 second. We then create 3 connections, and release them
10+
* after 1 second, we then check that the pool has 0 connections, and 0
11+
* free connections.
12+
*
13+
* @see https://github.com/sidorares/node-mysql2/issues/3020
14+
*/
15+
16+
/**
17+
* This test case
18+
*/
19+
const pool = new createPool({
20+
connectionLimit: 3,
21+
maxIdle: 2,
22+
idleTimeout: 1000,
23+
});
24+
25+
/**
26+
* Create the first connection and ensure it's in the pool as expected
27+
*/
28+
pool.getConnection((err1, connection1) => {
29+
assert.ifError(err1);
30+
assert.ok(connection1);
31+
32+
/**
33+
* Create the second connection and ensure it's in the pool as expected
34+
*/
35+
pool.getConnection((err2, connection2) => {
36+
assert.ifError(err2);
37+
assert.ok(connection2);
38+
39+
/**
40+
* Create the third connection and ensure it's in the pool as expected
41+
*/
42+
pool.getConnection((err3, connection3) => {
43+
assert.ifError(err3);
44+
assert.ok(connection3);
45+
46+
/**
47+
* Release all the connections
48+
*/
49+
connection1.release();
50+
connection2.release();
51+
connection3.release();
52+
53+
/**
54+
* After the idle timeout has passed, check that all items in the in the pool
55+
* that have been released are destroyed as expected.
56+
*/
57+
setTimeout(() => {
58+
assert(
59+
pool._allConnections.length === 0,
60+
`Expected all connections to be closed, but found ${pool._allConnections.length}`,
61+
);
62+
assert(
63+
pool._freeConnections.length === 0,
64+
`Expected all free connections to be closed, but found ${pool._freeConnections.length}`,
65+
);
66+
67+
pool.end();
68+
}, 5000);
69+
});
70+
});
71+
});
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.test.cjs').createPool;
4+
const { assert } = require('poku');
5+
6+
const pool = new createPool({
7+
connectionLimit: 3, // 5 connections
8+
maxIdle: 1, // 1 idle connection
9+
idleTimeout: 1000, // remove idle connections after 1 second
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+
// after two seconds, the above 3 connection should have been destroyed
30+
setTimeout(() => {
31+
assert(pool._allConnections.length === 0);
32+
assert(pool._freeConnections.length === 0);
33+
// Creating a new connection should create a fresh one
34+
pool.getConnection((err4, connection4) => {
35+
assert.ifError(err4);
36+
assert.ok(connection4);
37+
assert(pool._allConnections.length === 1);
38+
assert(pool._freeConnections.length === 0);
39+
connection4.release();
40+
connection4.destroy();
41+
pool.end();
42+
});
43+
}, 2000);
44+
});
45+
});
46+
});

test/integration/test-pool-release-idle-connection.test.cjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ pool.getConnection((err1, connection1) => {
3939
connection4.destroy();
4040
pool.end();
4141
});
42-
}, 7000);
42+
// Setting the time to a lower value than idleTimeout will ensure that the connection is not considered idle
43+
// during our assertions
44+
}, 4000);
4345
});
4446
});
4547
});

0 commit comments

Comments
 (0)