0
votes

I'm quite new to async, await and promises. I have an example code here:

export function pollSqsQueue(): Promise<void> {
  return receiveMessageFromQueue()
    .then((res) => res.Messages || [])
    .then(filterMessages)
    .then(mapMessagesToObjects)
    .then(saveObjects)
    .then(deleteMessagesFromQueue)
    .catch((error) => {
      appLogger.error('Unexpected error when handling queue', error);
    });
}

Basically the problem / question is, that if error is thrown in async saveObjects function, why is the deleteMessagesFromQueue still executed? In my understanding it should jump directly to catch block and just log the error.

Edit: the error is actually thrown in here and saveObjects use this function through another async function. Error is not catched anywhere except in the chain above:

export const upsert: (
  conn: PoolConnection,
  table: string,
  fields: string[],
  params: any[],
) => Promise<OkPacket> = async (conn, table, fields, params) => {
  const sql = `
    INSERT INTO
      ${table} (${fields.join(',')})
    VALUES (${', ?'.repeat(fields.length).slice(2)})
    ON DUPLICATE KEY UPDATE ${fields.map((field) => `${field}=VALUES(${field})`).join(', ')}
  `;
  const [result] = await conn.execute<OkPacket>(sql, params);
  return result;
};

So if some fields are missing, the upsert will fail and error is thrown. Only thing I get into logs is:

"message":"unhandled promise rejection, promise:{}

1
Is saveObjects asynchronous? is the error thrown asynchronously in this function?IAmDranged
You would have to show us the code for the .then() handlers you're asking about. If saveObjects rejects or throws correctly, then it absolutely will skip deleteMessagesFromQueue and go right to the .catch() handler. So, if it's not doing so, then we need to see the code for saveObjects because it is apparently not behaving the way you think it is. For example, if you have a plain asynchronous callback in saveObjects and you're throwing in there, that won't be caught by anything.jfriend00
Yes, saveObjects is asynchronous. The errors is actually thrown deeper in db level, which also is async function :).user2890128

1 Answers

0
votes

Just written a small program to further illustrate my comment to your question:

// index.js
var p1 = Promise.resolve()
var useAsyncCallback = process.argv[2] == "true" ? true : false

p1
    .then(() => {
        if (useAsyncCallback) return setTimeout(() => { throw new Error() }, 10)
        throw new Error()
    })
    .then(() => console.log("Executed"))
    .catch(() => console.error("Error in the chain"))

process.setUncaughtExceptionCaptureCallback(function (error) {
    console.error("Exception has reached the global scope.")
})

It runs in two different modes - synchronous and asynchronous - resulting in two different outputs:

node index false   
// output: Error in the chain
node index true
// output: Executed
//         Exception has reached the global scope.

Edit: here is the new version of the program accounting for async functions - returning a promise - which is your error scenario.

var p1 = Promise.resolve()
var mode = process.argv[2] || "synchronous"
console.log("Running in " + mode + " mode.")
p1
    .then(() => {
        if (mode == "asynchronous") return setTimeout(() => { throw new Error() }, 10)
        if (mode == "synchronous") throw new Error()
        if (mode == "promise") new Promise((_, reject) => { setTimeout(() => { reject(new Error()) }, 10) })
    })
    .then(() => console.log("Executed"))
    .catch(() => console.error("Error in the chain"))

process.setUncaughtExceptionCaptureCallback(() => console.error("Exception has reached the global scope."))
process.on('unhandledRejection', () => console.error("Rejection unhandled."))

And here are the outputs:

node index synchronous
// Output: Running in synchronous mode.
//         Error in the chain
node index asynchronous
// Output: Running in asynchronous mode.
//         Executed
//         Exception has reached the global scope.
node index promise
// Output: Running in promise mode.
//         Executed
//         Rejection unhandled.

In your scenario, it sounds like the promise returned by the upsert() function is not properly handled in case it rejects. The caller of this function should take appropriate action - ie either set a then/catch callback for the returned promise, or await and wrap it into a try/catch block if the caller is itself an async function. Another possibility would be for the caller to just return the promise and let the client code of the caller handle any rejection.

Hopefully that helps.