Skip to content

Awaiting on pgcursor.close may never resolve #2642

Open
@FreeSlave

Description

@FreeSlave

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').

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions