Search code examples
javascriptnode.jspromiseasync-awaites6-promise

How to ensure a code execution only after the await-function is done?


In case my Node.js v.13.12 app faces some technical issue, I'd like:

  1. to write a log message in the DB;
  2. to exit from the Node.js app with a specific code.

To achieve such behaviour I use the following code:

const onError = async function onError(error) {

    await logger.log("Critical error: " + error);

    process.exit(UNCAUGHT_FATAL_EXCEPTION);
}

The problem is that when I execute the code above, I reach await logger.log(…), go inside and then immediately continue to process.exit(UNCAUGHT_FATAL_EXCEPTION) and execute it.

As a result, the app is getting closed before the writing to the DB is finished, although I expect from await to wait until the logger.log(…) is done.

How to ensure that process.exit(UNCAUGHT_FATAL_EXCEPTION) will be executed only after logger.log(…) is done without using a callback?

Update:
The entire logger.log(…) code-chain:

export const log = async function log(source, severityNum, severityLevel, limitSeverityNum, functionName, message) {

    if ((severityNum > LOG_LEVELS.OFF.intLevel) && (severityNum <= limitSeverityNum)) {

        await writeLogToDB(source, severityNum, severityLevel, functionName, message);

    }

};

const writeLogToDB = async function writeLogToDB(source, severityNum, severityLevel, functionName, message) {

    try {

        const con = await getConnection();

        con.connect(function (err) {

            if (err) throw err;

            con.query(qryDict.QUERIES.setAddNewLog, [source, severityNum, severityLevel, functionName, message], function (err) {

                try {
                    if (err) {
                        console.error("addNewLog", err);
                    }
                    let response = JSON.stringify({
                        "result": true,
                        "message": "success"
                    });
                } catch (err) {
                    let response = JSON.stringify({
                        "result": false,
                        "message": err
                    });
                    return response;
                } finally {
                    con.close();
                }
            });
        });
    } catch (err) {
        con.close();
        console.error(err);
    }
};

Solution

  • The problem is in the writeLogToDB function.

    The function is async, but internally it uses the con.connect callback-based mechanism, which no code is await-ing on.

    You have to use promises all the way for the await-ing to propagate:

    const writeLogToDB = async function writeLogToDB(
      source,
      severityNum,
      severityLevel,
      functionName,
      message
    ) {
      const con = await getConnection();
    
      return new Promise((resolve, reject) => {
        con.connect(function(err) {
          if (err) return reject(err);
    
          con.query(
            qryDict.QUERIES.setAddNewLog,
            [source, severityNum, severityLevel, functionName, message],
            function(err) {
              if (err) return reject(err);
    
              resolve(
                JSON.stringify({
                  result: true,
                  message: "success"
                })
              );
            }
          );
        });
      }).finally(() => {
        // note: add a check here to do it only
        // if connection is opened to handle edge cases
        con.close();
      });
    };
    

    A cleaner solution would be to implement the connection methods themselves to be promise-based, not callback. (maybe util/promisify can help)

    Then you'd have cleaner code:

    const writeLogToDB = async function writeLogToDB(
      source,
      severityNum,
      severityLevel,
      functionName,
      message
    ) {
      const con = await getConnection();
    
      try {
        await con.connect();
        await con.query(qryDict.QUERIES.setAddNewLog, [
          source,
          severityNum,
          severityLevel,
          functionName,
          message
        ]);
        return JSON.stringify({
          result: true,
          message: "success"
        });
      } finally {
        // note: add a check here to do it only
        // if connection is opened to handle edge cases
        con.close();
      }
    };