From 823153138fefc63c5767508d5522cdf58902b1f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Bra=C5=A1na?= Date: Fri, 14 Feb 2020 17:23:41 +0100 Subject: [PATCH] Destroy socket when there was an error on it (#1975) When error happens on socket, potentially dead socket is kept open indefinitely by calling "connection.end()". Similar issue is that it keeps socket open until long-running query is finished even though the connection was ended. --- packages/pg/lib/client.js | 2 +- .../connection-pool/error-tests.js | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/pg/lib/client.js b/packages/pg/lib/client.js index 93807e48..05efbdc5 100644 --- a/packages/pg/lib/client.js +++ b/packages/pg/lib/client.js @@ -545,7 +545,7 @@ Client.prototype.query = function (config, values, callback) { Client.prototype.end = function (cb) { this._ending = true - if (this.activeQuery) { + if (this.activeQuery || !this._queryable) { // if we have an active query we need to force a disconnect // on the socket - otherwise a hung query could block end forever this.connection.stream.destroy() diff --git a/packages/pg/test/integration/connection-pool/error-tests.js b/packages/pg/test/integration/connection-pool/error-tests.js index 597c29b3..9fe76043 100644 --- a/packages/pg/test/integration/connection-pool/error-tests.js +++ b/packages/pg/test/integration/connection-pool/error-tests.js @@ -1,6 +1,7 @@ 'use strict' var helper = require('./test-helper') const pg = helper.pg +const native = helper.args.native const suite = new helper.Suite() suite.test('connecting to invalid port', (cb) => { @@ -99,3 +100,31 @@ suite.test('connection-level errors cause future queries to fail', (cb) => { })) })) }) + +suite.test('handles socket error during pool.query and destroys it immediately', (cb) => { + const pool = new pg.Pool({ max: 1 }) + + if (native) { + pool.query('SELECT pg_sleep(10)', [], (err) => { + assert.equal(err.message, 'canceling statement due to user request') + cb() + }) + + setTimeout(() => { + pool._clients[0].native.cancel((err) => { + assert.ifError(err) + }) + }, 100) + } else { + pool.query('SELECT pg_sleep(10)', [], (err) => { + assert.equal(err.message, 'network issue') + assert.equal(stream.destroyed, true) + cb() + }) + + const stream = pool._clients[0].connection.stream + setTimeout(() => { + stream.emit('error', new Error('network issue')) + }, 100) + } +})