17

I am trying to create a database setup script for a nodeJS project. I have the following async function createTable that queries a PostgreSQL database.

The problem is that the script does not quit after all the operations have been carried out. I have tried appending process.exit(0) to the end of the file but that just prematurely kills the script (I think it executes while the async operations are running).

How do I properly exit the script after operations are done?

const dbInit = () => {
  const createTable = async (creationQuery, tableName) => {
    try {
      const created = await client.query(creationQuery);
      if (created) logger(`'${tableName}' table created successfully`);
    } catch (err) {
      logger(err.message);
    }
  };

  createTable(Schemas.userModel, 'Users');
  createTable(Schemas.orderModel, 'Orders');
};
dbInit();
Oguntoye
  • 645
  • 1
  • 7
  • 19
  • 1
    Possible duplicate of [Exit from a NodeJS script when all asynchronous tasks are done](https://stackoverflow.com/questions/43870227/exit-from-a-nodejs-script-when-all-asynchronous-tasks-are-done) – MatthewG Sep 22 '18 at 21:45
  • 1
    Something is keeping your script running. Could for example be an open database connection, or a timer event. See https://www.npmjs.com/package/wtfnode – Evert Sep 22 '18 at 21:52
  • `Promise.all([createTable(…), createTable(…)]).then(() => process.exit(0), err => { console.error(err); process.exit(1); })` – Bergi Sep 22 '18 at 21:56

2 Answers2

38

Node.js exits when event loop runs dry. If the script doesn't exit after async function ends, this means that there is something that prevents it from being completed.

In this case there are database queries but database connection isn't closed, this is the cause. Also control flow is messed up, there's no resulting promise to chain.

It should be:

  const createTable = async (creationQuery, tableName) => {
    try {
      const created = await client.query(creationQuery);
      if (created) logger(`'${tableName}' table created successfully`);
    } catch (err) {
      logger(err.message);
    }
  };

const dbInit = async () => {
  try {
    await createTable(Schemas.userModel, 'Users');
    await createTable(Schemas.orderModel, 'Orders');
    process.exit(0);
    // or close database connection
  } catch (err) {
    process.exit(1);
  }
};
dbInit();

All rejections should be handled with either promise catch() or try..catch. Not handling them in this case can result in UnhandledPromiseRejectionWarning console output and the script that never exits.

Dexygen
  • 12,287
  • 13
  • 80
  • 147
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
1

This solution avoids adding process.exit on each block of the try-catch

const dbInit = async () => {
  const createTable = async (creationQuery, tableName) => {
    try {
      const created = await client.query(creationQuery);
      if (created) logger(`'${tableName}' table created successfully`);
    } catch (err) {
      logger(err.message);
    }
  };

  await createTable(Schemas.userModel, 'Users');
  await createTable(Schemas.orderModel, 'Orders');
};

dbInit().finally(() => {
  process.exit();
});
kato2
  • 535
  • 4
  • 15