vitaly-t/pg-promise

Can't forcibly close connection after creating a template DB

TheRealChssAddct opened this issue · 1 comments

Expected behavior

I have code which ensures the templates exist on an arbitrary postgres server.
Users can create new databases from those templates - either through a front-end gui calling an API on their behalf, or they can call the API directly.
I have ensure code which creates the template DBs with the following procedure:

Connect to the server to postgres db (dbConn1) and create the new template db.
Connect to the server with the name of the newly created template (dbConn2).
Execute scripts which generate the necessary tables, functions, data of the template db.
Later, on dbConn1, create the new database from the newly created template DB.
A new database should be successfully created from the newly created template DB.

Actual behavior

The template DB is successfully created, but the connection (dbConn2) is not successfully disconnected.

When dbConn1 tries to create the new database from the template, I get an error with message:

source database \"template_12_with_default_data\" is being accessed by other users

and error detail:

There are 2 other sessions using the database.

Steps to reproduce

My sample code

` relevant portion of ensureTemplateDB function, which does work (create the template dbs):

const { info, dbConn } = getDefaultDatabaseConnection(connectionString);

// create the template database:
try {
    const createQuery = 'create database $1:name with is_template = true';
    await dbConn.none(createQuery, [templateDbName]);

    // ${friendlyName};${defaultSchema} must be part of the query string, not an arg. frustratingly.
    const commentQuery = `comment on database $1:name is '${friendlyName};${defaultSchema}'`;
    await dbConn.none(commentQuery, [templateDbName]);

    let { dbConn: templateDbConn } = getSpecificDatabaseConnection(connectionString, templateDbName);
    const templateContents = readFileSync(path.join(__dirname, templateScriptFile), 'utf8');

    let directConnection: any; // shared connection object;
    await templateDbConn.connect({direct: true})
        .then((obj: any) => {
            directConnection = obj;
            return directConnection.none(templateContents);
        })
        .finally(() => {
            // release the connection
            if (directConnection) {
              directConnection.done(true); // try this way
        }
    });

    await templateDbConn.$pool.end(); // try this way
} catch(err) {
    throw { name: err, message: 'postgres-create-template-database-error' };
}

`

` relevant portion of createDb function, called after the loop which ensures the multiple template DBs :

// actually create the database:
try {
    const createQuery = 'create database $1:name with template $2:name owner $3:name';
    await dbConn.none(createQuery, [ databaseName, templateName, dbMainUser ]);
    // Error occurs here ^^^^^

    const revokePubQuery = 'revoke all on database $1:name from public';
    await dbConn.none(revokePubQuery, [ databaseName ]);

    // Set the search_path to the default schema
    if (existingTemplate) {
        const schemaQuery = 'alter database $1:name set search_path to $2:name;';
      await dbConn.none(schemaQuery, [ databaseName, existingTemplate.schema ]);
    }
} catch(err) {
    throw { name: err, message: 'postgres-create-database-error' };
}

`

Environment

  • Version of pg-promise:
  • "pg-promise": "^10.11.1",
  • OS type (Linux/Windows/Mac):
  • Linux
  • Version of Node.js:
  • v14.19.0

the problem turned out to be the arbitrary server i was testing with had pgbouncer running. The direct connection code above for closing the connection was working fine. It was pgbouncer that was maintaining the open connection.