From 63e151503d882d808111520e748aff9cd15b4451 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Mon, 3 Oct 2022 11:17:37 +0300 Subject: [PATCH] Cursor: avoid closing connection twice if error received after destroy() --- packages/pg-cursor/index.js | 3 ++ packages/pg-query-stream/test/error.ts | 42 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/packages/pg-cursor/index.js b/packages/pg-cursor/index.js index 9bbda641a..bed5779f5 100644 --- a/packages/pg-cursor/index.js +++ b/packages/pg-cursor/index.js @@ -151,6 +151,9 @@ class Cursor extends EventEmitter { } handleError(msg) { + // If this cursor has already closed, don't try to handle the error. + if(this.state === 'done') return; + // If we're in an initialized state we've never been submitted // and don't have a connection instance reference yet. // This can happen if you queue a stream and close the client before diff --git a/packages/pg-query-stream/test/error.ts b/packages/pg-query-stream/test/error.ts index 220a52485..823fb0ef0 100644 --- a/packages/pg-query-stream/test/error.ts +++ b/packages/pg-query-stream/test/error.ts @@ -89,4 +89,46 @@ describe('error recovery', () => { await client.end() }) }) + + it('should work if used after timeout error', async () => { + const pool = new Pool({ max: 1, connectionTimeoutMillis: 400, statement_timeout: 400 }); + + const res1 = await pool.query('SELECT 1 AS a'); + assert.deepStrictEqual(res1.rows, [ { a:1 } ]); + + const query = new QueryStream('SELECT 2 AS b'); + const client = await pool.connect(); + const stream = await client.query(query); + + await assert.rejects(() => pool.query('SELECT TRUE'), { message: 'timeout exceeded when trying to connect' }); + + await stream.destroy(); + await client.release(); + + const res2 = await pool.query('SELECT 4 AS d'); + assert.deepStrictEqual(res2.rows, [ { d:4 } ]); + + await pool.end(); + }) + + it('should work if used after syntax error', async () => { + const pool = new Pool({ max: 1, statement_timeout: 100 }); // statement_timeout is required here, so maybe this is just another timeout error? + + const res1 = await pool.query('SELECT 1 AS a'); + assert.deepStrictEqual(res1.rows, [ { a:1 } ]); + + const query = new QueryStream('SELECT 2 AS b'); + const client = await pool.connect(); + const stream = await client.query(query); + + await new Promise(resolve => setTimeout(resolve, 10)); + + await stream.destroy(); + await client.release(); + + const res2 = await pool.query('SELECT 4 AS d'); + assert.deepStrictEqual(res2.rows, [ { d:4 } ]); + + await pool.end(); + }) })