3

I am struggling with async await try catch block for a couple of days.

async function executeJob(job) {

  // necessary variable declaration code here

  try {
    do {
      let procedureRequests = await ProcedureRequestModel.find(filter, options);

      // doing process here...

    } while (fetchedCount < totalCount);

    providerNPIIds = [...providerNPIIds];

    // Fetch provider details
    let providerDetails = await esHelper.getProvidersById(providerNPIIds, true);

    try {

      let updateProviderCount = await UserProvider.updateAll(
          {
            userId: userId
          },
          {
            providers: providerNPIIds,
            countByType: providerCountType
          });

      if(updateProviderCount) {
        try {
          let destroyJobId = await  app.models.Job.destroyById(job.idd);
        } catch (e) {
          var err = new QueueError();
          console.log(err instanceof QueueError);
          throw new QueueError();
        }

      }
    } catch (e) {
      logger.error('Failed to update UserProviders  & Count: %O', err);
      throw e;
    }

    executeNextJob();
  } catch (e) {
    if(e instanceof QueueError) {
      console.log('Exiting from process');
      process.exit(1);
    } else {
      console.log('Working Code');
      buryFailedJobAndExecuteNext(job);
    }

  }
}

Is my try catch in this async function proper?

This is how I created Custom Error Class and exported globally.

// error.js file

class QueueError extends Error {

}

global.QueueError = QueueError;

The requirement:

Intentionally changed job.id to job.idd in

let destroyJobId = await  app.models.Job.destroyById(job.idd); 

so that I can catch error. If there is error then throw newly created custom Error class. But throwing QueueError will cause logging

logger.error('Failed to update UserProviders  & Count: %O', err); 

too , even though no need to catch error there, since try block is working If I throw QueueError I only wants to catch error in last catch block only.

Below is the callback version, I am converting it into async await.

 Updating providersNPIId & category count
     UserProvider.updateAll({userId: userId},
       {
         providers: providerNPIIds,
         countByType: providerCountType,
       }, function(err, data) {
         if (err) {
           logger.error('Failed to update UserProviders  & Count: %O', err);
           // throw new QueueError();
         }
         // Remove countProvider Job
         app.models.Job.destroyById(job.id, function(err) {
           if (err) {
             logger.error('Failed to remove countProvider job: %O', err);

           }
         });
       });
James Z
  • 12,209
  • 10
  • 24
  • 44
Vishnu
  • 704
  • 12
  • 34
  • what is the actual issue ? – Kunal Mukherjee Jun 04 '19 at 13:31
  • @KunalMukherjee : If QueueError is thrown, I need to go to last catch block for handling the error. Now the case is logger error with Failed to remove section is catching. – Vishnu Jun 04 '19 at 13:34
  • you can refactor your code into smaller chunks and include a try-catch in each chunk – Kunal Mukherjee Jun 04 '19 at 13:36
  • @KunalMukherjee : Can you please show me the updated code. Please.. – Vishnu Jun 04 '19 at 13:37
  • What is the use of `procedureRequests` ? I dont see any references to this variable – Kunal Mukherjee Jun 04 '19 at 13:38
  • @KunalMukherjee: You can ignore the variables and all. Code is working. But i am not sure about the working of catch block and how they handle errors in async await – Vishnu Jun 04 '19 at 13:39
  • Have a look at [Correct Try…Catch Syntax Using Async/Await](https://stackoverflow.com/q/44663864/1048572) for ways to properly distinguish error from success cases. – Bergi Jun 04 '19 at 20:12

2 Answers2

1

You can refactor your code in smaller functions that return a promise for which you can locally wrap try-catch and handle it.

async function executeJob(job) {

  // necessary variable declaration code here
  try {

    await doProcedure();

    providerNPIIds = [...providerNPIIds];

    // Fetch provider details
    let providerDetails = await esHelper.getProvidersById(providerNPIIds, true);
    const updateProviderCount = await getProviderCount(userId, providerNPIIds, providerCountType);

    if(updateProviderCount) {
        await destroyJobById(job.idd);
    }

    executeNextJob();
  } catch (e) {
    if(e instanceof QueueError) {
      console.log('Exiting from process');
      process.exit(1);
    } else {
      console.log('Working Code');
      buryFailedJobAndExecuteNext(job);
    }
  }
}

async function doProcedure() {
    try {
        do {
          let procedureRequests = await ProcedureRequestModel.find(filter, options);

          // doing process here...

        } while (fetchedCount < totalCount);
    } catch (err) {
        throw err;
    }
}

async function getProviderCount(userId, providerNPIIds, providerCountType) {
    try {
        let updateProviderCount = await UserProvider.updateAll({ userId: userId }, { providers: providerNPIIds, countByType: providerCountType });
        return updateProviderCount;
    } catch (err) {
      logger.error('Failed to update UserProviders  & Count: %O', err);
      throw e;
    }
}

async function destroyJobById(Id) {
    try {
          let destroyJobId = await app.models.Job.destroyById(Id);
    } catch (err) {
          throw err;
    }
}
Kunal Mukherjee
  • 5,775
  • 3
  • 25
  • 53
  • how to throw QueueError properly, ny code won't work if i remove var err = new QueueError(); Can you please tell me why – Vishnu Jun 04 '19 at 13:55
  • @Vishnu modified the `destroyJobById(Id)` method – Kunal Mukherjee Jun 04 '19 at 14:01
  • one more doubt. Can i.create a custom error class like this without creating construction function. Also if destroyByid fails i need to throw QueueError why there is checking instance for that? I didnt get the code. Can u please explain – Vishnu Jun 04 '19 at 14:10
  • 1
    @KunalMukherjee so why would you catch a `QueueError` and then rethrow it (and as a result throwing away the error stack :/)? – James Jun 04 '19 at 14:15
  • @James Just throwing the exception now, the handling part can be done in the main invoking function – Kunal Mukherjee Jun 04 '19 at 15:10
  • @KunalMukherjee why you removed new QueueError? – Vishnu Jun 04 '19 at 15:23
  • @Vishnu Because if its `QueueError` then it will get automatically thrown and handled in your invoking function – Kunal Mukherjee Jun 04 '19 at 15:32
  • @KunalMukherjee In my code i have catch 3 catch block. Can you please tell me the catch control flow here. Because if destroyById fails then failed to update error will catch that if we throw it, right? But I need last catch block to catch destroyByJob error. How can i do that? – Vishnu Jun 04 '19 at 15:40
  • @KunalMukherjee why would you catch an error _just_ to rethrow? I'm really not seeing the purpose of `destroyJobById` – James Jun 04 '19 at 15:40
0

This is basically the same what You have:

1 function myFunctionPromise() {                                                                                     
2   return new Promise((response, reject) => {                                                                       
3       setTimeout(() => reject("Reject Err"), 3000);                                                                
4   });                                                                                                              
5 } 

7 async function myFunction() {                                                                                      
8      try {                                                                                                         
9        try {                                                                                                       
10          await myFunctionPromise();                                                                                
11        } catch(e) {                                                                                                
12          console.log("Second Err");                                                                                
13          throw e;                                                                                                  
14        }
15 
16      } catch (e) {                                                                                                 
17        throw e;
18      }
19 
20      console.log("test");
21 }
22 
23 
24 myFunction()

The only difference I see it's the Reject of the promise line #3. So I'm wondering if:

let destroyJobId = await app.models.Job.destroyById(job.idd);

It's rejecting properly the promise.