Skip to content

Commit 8206f7a

Browse files
author
maxbronnikov10
committed
fix: Connection timeout handling for native clients in connected state
Now, when using the native client with a connection timeout, the pool could incorrectly destroy or end a client that was already connected, due to not distinguishing between connection states. This caused issues such as brianc/node-pg-native#49, where a native client that had already established a connection could be forcefully closed if the connection callback was delayed past the timeout.
1 parent fab87b2 commit 8206f7a

File tree

3 files changed

+38
-4
lines changed

3 files changed

+38
-4
lines changed

packages/pg-pool/index.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,16 @@ class Pool extends EventEmitter {
241241
let timeoutHit = false
242242
if (this.options.connectionTimeoutMillis) {
243243
tid = setTimeout(() => {
244-
this.log('ending client due to timeout')
245-
timeoutHit = true
246-
// force kill the node driver, and let libpq do its teardown
247-
client.connection ? client.connection.stream.destroy() : client.end()
244+
if (client.connection) {
245+
this.log('ending client due to timeout')
246+
timeoutHit = true
247+
client.connection.stream.destroy()
248+
} else if (!client.isConnected()) {
249+
this.log('ending client due to timeout')
250+
timeoutHit = true
251+
// force kill the node driver, and let libpq do its teardown
252+
client.end()
253+
}
248254
}, this.options.connectionTimeoutMillis)
249255
}
250256

packages/pg-pool/test/connection-timeout.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,4 +226,25 @@ describe('connection timeout', () => {
226226
})
227227
})
228228
})
229+
230+
it('should connect if timeout is passed, but native client in connected state', (done) => {
231+
const Client = require('pg').native.Client
232+
233+
Client.prototype.connect = function (cb) {
234+
this._connected = true
235+
236+
return setTimeout(() => {
237+
cb()
238+
}, 200)
239+
}
240+
241+
const pool = new Pool({ connectionTimeoutMillis: 100, port: this.port, host: 'localhost' }, Client)
242+
243+
pool.connect((err, client, release) => {
244+
expect(err).to.be(undefined)
245+
expect(client).to.not.be(undefined)
246+
expect(client.isConnected()).to.be(true)
247+
done()
248+
})
249+
})
229250
})

packages/pg/lib/native/client.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,10 @@ Client.prototype.end = function (cb) {
250250
cb = (err) => (err ? reject(err) : resolve())
251251
})
252252
}
253+
253254
this.native.end(function () {
255+
self._connected = false
256+
254257
self._errorAllQueries(new Error('Connection terminated'))
255258

256259
process.nextTick(() => {
@@ -306,3 +309,7 @@ Client.prototype.setTypeParser = function (oid, format, parseFn) {
306309
Client.prototype.getTypeParser = function (oid, format) {
307310
return this._types.getTypeParser(oid, format)
308311
}
312+
313+
Client.prototype.isConnected = function () {
314+
return this._connected
315+
}

0 commit comments

Comments
 (0)