Skip to content

Commit 4e35226

Browse files
charmanderbrianc
authored andcommitted
Fix client remove clearing unrelated idle timers (#71)
* Add failing test for idle timer continuation after removal * Clear idle timeout only for removed client * Copy list of idle clients for modification during iteration
1 parent c3417e9 commit 4e35226

File tree

2 files changed

+43
-5
lines changed

2 files changed

+43
-5
lines changed

index.js

+18-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ const EventEmitter = require('events').EventEmitter
33

44
const NOOP = function () { }
55

6+
const removeWhere = (list, predicate) => {
7+
const i = list.findIndex(predicate)
8+
9+
return i === -1
10+
? undefined
11+
: list.splice(i, 1)[0]
12+
}
13+
614
class IdleItem {
715
constructor (client, timeoutId) {
816
this.client = client
@@ -80,7 +88,7 @@ class Pool extends EventEmitter {
8088
if (this.ending) {
8189
this.log('pulse queue on ending')
8290
if (this._idle.length) {
83-
this._idle.map(item => {
91+
this._idle.slice().map(item => {
8492
this._remove(item.client)
8593
})
8694
}
@@ -114,10 +122,15 @@ class Pool extends EventEmitter {
114122
}
115123

116124
_remove (client) {
117-
this._idle = this._idle.filter(item => {
118-
clearTimeout(item.timeoutId)
119-
return item.client !== client
120-
})
125+
const removed = removeWhere(
126+
this._idle,
127+
item => item.client === client
128+
)
129+
130+
if (removed !== undefined) {
131+
clearTimeout(removed.timeoutId)
132+
}
133+
121134
this._clients = this._clients.filter(c => c !== client)
122135
client.end()
123136
this.emit('remove', client)

test/idle-timeout.js

+25
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,31 @@ describe('idle timeout', () => {
2020
})
2121
})
2222

23+
it('times out and removes clients when others are also removed', co.wrap(function * () {
24+
const pool = new Pool({ idleTimeoutMillis: 10 })
25+
const clientA = yield pool.connect()
26+
const clientB = yield pool.connect()
27+
clientA.release()
28+
clientB.release(new Error())
29+
30+
const removal = new Promise((resolve) => {
31+
pool.on('remove', () => {
32+
expect(pool.idleCount).to.equal(0)
33+
expect(pool.totalCount).to.equal(0)
34+
resolve()
35+
})
36+
})
37+
38+
const timeout = wait(100).then(() =>
39+
Promise.reject(new Error('Idle timeout failed to occur')))
40+
41+
try {
42+
yield Promise.race([removal, timeout])
43+
} finally {
44+
pool.end()
45+
}
46+
}))
47+
2348
it('can remove idle clients and recreate them', co.wrap(function * () {
2449
const pool = new Pool({ idleTimeoutMillis: 1 })
2550
const results = []

0 commit comments

Comments
 (0)