From 8a7b43aa7e509797e6d61ba9c17d0cca4c4355a1 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Wed, 26 Feb 2020 11:47:40 -0600 Subject: [PATCH 1/2] Attempt to handle a stream being silently killed in the background --- packages/pg-pool/index.js | 15 +++++++-- .../test/background-socket-terminiation.js | 31 +++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 packages/pg-pool/test/background-socket-terminiation.js diff --git a/packages/pg-pool/index.js b/packages/pg-pool/index.js index 83ec51e09..eb5181fb5 100644 --- a/packages/pg-pool/index.js +++ b/packages/pg-pool/index.js @@ -116,11 +116,20 @@ class Pool extends EventEmitter { const pendingItem = this._pendingQueue.shift() if (this._idle.length) { const idleItem = this._idle.pop() - clearTimeout(idleItem.timeoutId) const client = idleItem.client - const idleListener = idleItem.idleListener + clearTimeout(idleItem.timeoutId) - return this._acquireClient(client, pendingItem, idleListener, false) + // TODO(bmc): we need a better state represetation on the client itself + // to indicate if it's connecting, idle, running a query, closed, etc... + // but for now we can look at it's stream. + // remove this client, it's died in the background - this can happen + // in aws lambdas - they go idle and the streams are closed without an error + if (client.connection.stream.readyState !== 'open') { + this._remove(client) + } else { + const idleListener = idleItem.idleListener + return this._acquireClient(client, pendingItem, idleListener, false) + } } if (!this._isFull()) { return this.newClient(pendingItem) diff --git a/packages/pg-pool/test/background-socket-terminiation.js b/packages/pg-pool/test/background-socket-terminiation.js new file mode 100644 index 000000000..15f3e8ac2 --- /dev/null +++ b/packages/pg-pool/test/background-socket-terminiation.js @@ -0,0 +1,31 @@ +'use strict' +const net = require('net') +const co = require('co') +const expect = require('expect.js') + +const describe = require('mocha').describe +const it = require('mocha').it + +const Pool = require('../') + +describe('a socket disconnecting in the background', () => { + it('should leave the pool in a usable state', async () => { + const pool = new Pool({ max: 1 }) + // just run any arbitrary query + const client = await pool.connect() + await client.query('SELECT NOW()') + // return the client + client.release() + + // now kill the socket in the background + client.connection.stream.end() + + // now try to query again, it should work + await pool.query('SELECT NOW()') + await pool.query('SELECT NOW()') + await pool.query('SELECT NOW()') + await pool.query('SELECT NOW()') + + await pool.end() + }) +}) From 31305dfb97bee59e4ec3a4a99d889bb982a9522e Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Wed, 26 Feb 2020 11:59:06 -0600 Subject: [PATCH 2/2] Dont detect error on native bindings right now --- packages/pg-pool/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/pg-pool/index.js b/packages/pg-pool/index.js index eb5181fb5..e45841e5f 100644 --- a/packages/pg-pool/index.js +++ b/packages/pg-pool/index.js @@ -121,10 +121,12 @@ class Pool extends EventEmitter { // TODO(bmc): we need a better state represetation on the client itself // to indicate if it's connecting, idle, running a query, closed, etc... - // but for now we can look at it's stream. + // as right now this hacky fix will only work for the JS client + // since the native client doesn't _have_ a connection property + // remove this client, it's died in the background - this can happen // in aws lambdas - they go idle and the streams are closed without an error - if (client.connection.stream.readyState !== 'open') { + if (client.connection && client.connection.stream.readyState !== 'open') { this._remove(client) } else { const idleListener = idleItem.idleListener