brianc / node-postgres

PostgreSQL client for node.js.
https://node-postgres.com
MIT License
12.04k stars 1.21k forks source link

[question] How to prevent database disconnects from crashing Node.js? #3260

Closed Darker closed 2 weeks ago

Darker commented 2 weeks ago

I have a simple express web app that runs an utility server. The whole app is basically just pg connection and a few Express json endpoints.

I used to have an issue where the database side would auto disconnect and the whole server would crash because of an error in pg. This is now occuring again. I think on the database server, some timeout was added which is kicking my app out.

This crash does not occur during a request but when the server is idle. How can I handle the forced disconnect so that nodejs keeps running?

Here's what it looks like:

node:events:492
      throw er; // Unhandled 'error' event
      ^

error: terminating connection due to administrator command
    at Parser.parseErrorMessage (/home/myuser/myproject/node_modules/pg-protocol/dist/parser.js:287:98)
    at Parser.handlePacket (/home/myuser/myproject/node_modules/pg-protocol/dist/parser.js:126:29)
    at Parser.parse (/home/myuser/myproject/node_modules/pg-protocol/dist/parser.js:39:38)
    at Socket.<anonymous> (/home/myuser/myproject/node_modules/pg-protocol/dist/index.js:11:42)
    at Socket.emit (node:events:514:28)
    at addChunk (node:internal/streams/readable:545:12)
    at readableAddChunkPushByteMode (node:internal/streams/readable:495:3)
    at Readable.push (node:internal/streams/readable:375:5)
    at TCP.onStreamRead (node:internal/stream_base_commons:190:23)
Emitted 'error' event on Client instance at:
    at Client._handleErrorEvent (/home/myuser/myproject/node_modules/pg/lib/client.js:341:10)
    at Client._handleErrorMessage (/home/myuser/myproject/node_modules/pg/lib/client.js:352:12)
    at Connection.emit (node:events:514:28)
    at /home/myuser/myproject/node_modules/pg/lib/connection.js:117:12
    at Parser.parse (/home/myuser/myproject/node_modules/pg-protocol/dist/parser.js:40:17)
    at Socket.<anonymous> (/home/myuser/myproject/node_modules/pg-protocol/dist/index.js:11:42)
    [... lines matching original stack trace ...]
    at Readable.push (node:internal/streams/readable:375:5) {
  length: 116,
  severity: 'FATAL',
  code: '57P01',
  detail: undefined,
  hint: undefined,
  position: undefined,
  internalPosition: undefined,
  internalQuery: undefined,
  where: undefined,
  schema: undefined,
  table: undefined,
  column: undefined,
  dataType: undefined,
  constraint: undefined,
  file: 'postgres.c',
  line: '3204',
  routine: 'ProcessInterrupts'
}

I want to handle any errors myself, probably by reconnecting. I am currently only using the pg package:

{
  "type": "module",
  "dependencies": {
    "pg": "^8.7.3",
    [...]
  }
brianc commented 2 weeks ago

There are kind of an annoying amount of places you need to add event listeners to prevent this. I'm going to adjust error handling to be easier in the future...for now you'll need to make sure you have an error handler added to the pool instance (if you're using a connection pool). Furthermore any manually created & connected clients which are idling must also have an error listener attached. Something like this should work:

const pool = new pg.Pool()
pool.on('error', () => {
  // error in background w/ idle clients in pool
})

// or if you have manual clients:

const client = new pg.Client()
await client.connect()
client.on('error', () => {
  // error on client while it was idle but connected to database
})

Those are the two places I believe you'll need an error event listener. Pls lmk if that doesn't work or you run into issuese with that. Sorry for the headache. I'm adjusting things in the future to where you wont need to have error listeners but I'm still working out the details (and it will be in a new semver major or opt-in only behavior since its a breaking, though good, change)