Retrying an async function on error, unhandled promise rejection

Solution for Retrying an async function on error, unhandled promise rejection
is Given Below:

This function is being called by a parent function, that should return the success object, or the error.

I’m having trouble using async while trying to retry a function 4 times. On success it’s all good. On error, I’m getting “Unhandled Promise Rejection”.

//create record
const createSFDCRecord = async (object, userData) => {
  console.log("trial", retryCount)
  return await conn.sobject(object).create(userData, async (err, ret) => {
    if (err || !ret.success) {
      if (retryCount < retryLimit) {
        setTimeout(async () => {
          return await createSFDCRecord(object, userData)
        }, 2000)
        retryCount++
      } else {
        pagerDutyEvent(
          `Failed to send ${userData.Trigger_Code_kcrm__c} form data into ${object} after 5x`,
          "error",
          err
        )
      }
    }
    console.log(`Created ${object} id : ${ret.id}`)
  })
}

sobject is from jsforce
http://jsforce.github.io/jsforce/doc/SObject.html

You are mixing promises with callbacks:

  • sobject(object).create returns a promise, so there is no need to use the callback argument.
  • return with a value has no sense in a setTimeout callback. That returned value is going nowhere.
  • The promises resulting from the repeated attempts are not chained: the resolution of the first is not locked into the next one. Instead you have a stand alone promise in a setTimeout callback, whose resolution or rejection is not handled.

The “Unhandled Promise Rejection” happens because you have an await of a promise that can reject, yet you do not capture the exception that will be triggered at that line when this happens.

You should refactor this to something like this (untested code):

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

const createSFDCRecord = async (object, userData) => {
    let retryCount = 1;
    while (true) {
        console.log("trial", retryCount);
        try {
            let ret = await conn.sobject(object).create(userData);
            if (!ret.success) throw new Error("ret.success is false");
            console.log(`Created ${object} id : ${ret.id}`);
            return ret.id;
        } catch(err) {
            if (retryCount >= retryLimit) {
                pagerDutyEvent(
                   `Failed to send ${userData.Trigger_Code_kcrm__c} form data into ${object} after ${retryLimit}x`,
                   "error",
                   err
                );
                return -1; // Or throw an exception... but then deal with it.
            }
        }
        retryCount++;
        await delay(2000);
    }
}