diff --git a/docs/pages/apis/pool.mdx b/docs/pages/apis/pool.mdx index 3627dd1c5..453c70fdf 100644 --- a/docs/pages/apis/pool.mdx +++ b/docs/pages/apis/pool.mdx @@ -240,7 +240,8 @@ The number of queued requests waiting on a client when all clients are checked o Whenever the pool establishes a new client connection to the PostgreSQL backend it will emit the `connect` event with the newly connected client. - The event listener does not wait for promises or async functions. If you want to run setup commands on each new client, use the `onConnect` option. (See documentation above.) + The event listener does not wait for promises or async functions. If you want to run setup commands on each new + client, use the `onConnect` option. (See documentation above.) ### acquire @@ -260,9 +261,8 @@ If the backend goes down or a network partition is encountered all the idle, con The error listener is passed the error as the first argument and the client upon which the error occurred as the 2nd argument. The client will be automatically terminated and removed from the pool, it is only passed to the error handler in case you want to inspect it. -
You probably want to add an event listener to the pool to catch background errors!
- Just like other event emitters, if a pool emits an error event and no listeners are added node will emit an - uncaught error and potentially crash your node process. + The pool has a default no-op error listener so an idle client error does not become an uncaught exception. Add your + own listener to observe, log, or otherwise handle these background errors.
### release diff --git a/packages/pg-pool/README.md b/packages/pg-pool/README.md index 80c644788..7d9538d0c 100644 --- a/packages/pg-pool/README.md +++ b/packages/pg-pool/README.md @@ -234,11 +234,14 @@ const pool = new Pool() // attach an error handler to the pool for when a connected, idle client // receives an error by being disconnected, etc pool.on('error', function (error, client) { - // handle this in the same way you would treat process.on('uncaughtException') + // observe or otherwise handle the background error // it is supplied the error as well as the idle client which received the error }) ``` +Pools include a default no-op error listener so an idle client error does not become an uncaught exception. Add your own +listener to observe, log, or otherwise handle these background errors. + #### connect Fired whenever the pool creates a **new** `pg.Client` instance and successfully connects it to the backend. diff --git a/packages/pg-pool/index.js b/packages/pg-pool/index.js index ab514fa88..7977c3a33 100644 --- a/packages/pg-pool/index.js +++ b/packages/pg-pool/index.js @@ -66,6 +66,7 @@ function makeIdleListener(pool, client) { class Pool extends EventEmitter { constructor(options, Client) { super() + this.on('error', () => {}) this.options = Object.assign({}, options) if (options != null && 'password' in options) { diff --git a/packages/pg-pool/test/events.js b/packages/pg-pool/test/events.js index 809c2159a..73c53b619 100644 --- a/packages/pg-pool/test/events.js +++ b/packages/pg-pool/test/events.js @@ -7,6 +7,26 @@ const it = require('mocha').it const Pool = require('../') describe('events', function () { + it('does not throw an unhandled error event', function () { + const pool = new Pool({ Client: mockClient() }) + const expectedError = new Error('unexpected idle client error') + + expect(() => pool.emit('error', expectedError)).to.not.throwException() + }) + + it('emits errors to user listeners', function () { + const pool = new Pool({ Client: mockClient() }) + const expectedError = new Error('unexpected idle client error') + let emittedError + + pool.on('error', function (error) { + emittedError = error + }) + pool.emit('error', expectedError) + + expect(emittedError).to.be(expectedError) + }) + it('emits connect before callback', function (done) { const pool = new Pool() let emittedClient = false diff --git a/packages/pg/lib/client.js b/packages/pg/lib/client.js index 2b13c1de7..df4207fc8 100644 --- a/packages/pg/lib/client.js +++ b/packages/pg/lib/client.js @@ -50,6 +50,7 @@ function coerceNumberOrDefault(value, defaultValue) { class Client extends EventEmitter { constructor(config) { super() + this.on('error', () => {}) this.connectionParameters = new ConnectionParameters(config) this.user = this.connectionParameters.user diff --git a/packages/pg/lib/native/client.js b/packages/pg/lib/native/client.js index 9ec3c8c03..3775edf42 100644 --- a/packages/pg/lib/native/client.js +++ b/packages/pg/lib/native/client.js @@ -22,6 +22,7 @@ const queryQueueLengthDeprecationNotice = nodeUtils.deprecate( const Client = (module.exports = function (config) { EventEmitter.call(this) + this.on('error', () => {}) config = config || {} this._Promise = config.Promise || global.Promise diff --git a/packages/pg/test/native/evented-api-tests.js b/packages/pg/test/native/evented-api-tests.js index 220fcaece..2e150e440 100644 --- a/packages/pg/test/native/evented-api-tests.js +++ b/packages/pg/test/native/evented-api-tests.js @@ -6,6 +6,26 @@ const assert = require('assert') const suite = new helper.Suite() const test = suite.test.bind(suite) +test('does not throw an unhandled error event', function () { + const client = new Client(helper.config) + const expectedError = new Error('unexpected idle client error') + + assert.doesNotThrow(() => client.emit('error', expectedError)) +}) + +test('emits errors to user listeners', function () { + const client = new Client(helper.config) + const expectedError = new Error('unexpected idle client error') + let emittedError + + client.on('error', (error) => { + emittedError = error + }) + client.emit('error', expectedError) + + assert.strictEqual(emittedError, expectedError) +}) + const setupClient = function () { const client = new Client(helper.config) client.connect() diff --git a/packages/pg/test/unit/client/configuration-tests.js b/packages/pg/test/unit/client/configuration-tests.js index 63d4ea649..d6549bc56 100644 --- a/packages/pg/test/unit/client/configuration-tests.js +++ b/packages/pg/test/unit/client/configuration-tests.js @@ -10,6 +10,26 @@ const pgdatabase = process.env['PGDATABASE'] || process.env.USER const pgport = process.env['PGPORT'] || 5432 test('client settings', function () { + test('does not throw an unhandled error event', function () { + const client = new Client() + const expectedError = new Error('unexpected idle client error') + + assert.doesNotThrow(() => client.emit('error', expectedError)) + }) + + test('emits errors to user listeners', function () { + const client = new Client() + const expectedError = new Error('unexpected idle client error') + let emittedError + + client.on('error', (error) => { + emittedError = error + }) + client.emit('error', expectedError) + + assert.strictEqual(emittedError, expectedError) + }) + test('defaults', function () { const client = new Client() assert.equal(client.user, pguser)