From 65df9052588296fc6e2a629885ab9b62cd3cd4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Bra=C5=A1na?= Date: Mon, 16 Sep 2019 23:41:45 +0200 Subject: [PATCH] Destroy socket when there was an error on it 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 93807e48c..05efbdc5a 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 597c29b38..9fe760431 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) + } +})