Description
I'm using pgcursor on Amazon Aurora PostgreSQL. If connection is terminated due to serverless scale event timeout, the promise returned by close
methods of the Cursor never resolves. Probably because it never gets the readyForQuery
event https://github.com/brianc/node-postgres/blob/master/packages/pg-cursor/index.js#L218
I made an assumption that the same can happen on regular postgresql if we manually abrupt the connection from the server side (terminating connection due to administrator command) while cursor is open and I was able to replicate it with this code (Obviously you need to fill configure clients with your settings):
const { Client } = require('pg')
const PgCursor = require('pg-cursor')
const client = new Client({
user: process.env.POSTGRES_USER,
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
password: process.env.POSTGRES_PASSWORD,
port: +(process.env.POSTGRES_PORT || 5432),
})
client.on('error', function(err: Error) {
console.error('In error handler:', err)
})
const terminatingClient = new Client({
user: process.env.POSTGRES_USER,
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
password: process.env.POSTGRES_PASSWORD,
port: +(process.env.POSTGRES_PORT || 5432),
})
terminatingClient.on('error', function(err: Error) {
console.error('terminatingClient In error handler:', err)
})
function terminatePostgresConnectionQuery(processID: number, db: string) {
return `SELECT pg_terminate_backend(pid) FROM
pg_stat_activity WHERE
pid = ${processID}
AND datname = '${db}';`
}
;(async() => {
try {
await client.connect()
await terminatingClient.connect()
const pgCursor = (client.query(
new PgCursor(`SELECT NOW()`)
))
console.log('Process id:', client.processID)
await terminatingClient.query(
terminatePostgresConnectionQuery(client.processID, process.env.POSTGRES_DATABASE ?? 'db'))
console.log('Made terminatingQuery')
await pgCursor.close()
console.log('cursor closed')
}
catch(err) {
console.error('In catch: ', err)
} finally {
try {
await client.query('SELECT NOW()')
} catch(err) {
console.error('Error in finally', err)
}
console.log('Exiting')
await client.end()
await terminatingClient.end()
}
})()
Here we create two connections. One is used to create a cursor and make a select query. Another is used to kill the first one via pg_terminate_backend
.
It never reaches console.log('cursor closed')
.