Search code examples
javascriptnode.jsfileasync-awaittimeout

Setting Timeout to fs.copy function


      global.resultArr = {};
      global.failedArr = [];
      global.successArr = [];    
       const writeFile = async function (dirResult, queryResult) {
  for (i = 0; i < queryResult.recordset.length; i++) {
    for (file of dirResult) {
      if (
        file.substring(file.length - 3) == "wav" &&
        global.failedArr.indexOf(queryResult.recordset[i].ip_vch) == -1
      ) {
        try {
          const writeResult = await timeout(
            fs.copy(
              dir + "//" + file,
              "//" +
                queryResult.recordset[i].ip_vch +
                "//RXWaveFiles//DynamicLibraries" +
                "//" +
                libid +
                "//" +
                file
            ),
            5000
          );
          if (
            writeResult &&
            global.failedArr.indexOf(queryResult.recordset[i].ip_vch) == -1
          ) {
            console.log(queryResult.recordset[i].ip_vch);
            global.failedArr.push(queryResult.recordset[i].ip_vch);
            await sql.query`update opower..dialers set fileMoveResult_int=0 where ip_vch =${queryResult.recordset[i].ip_vch}`;
          } else if (
            global.successArr.indexOf(queryResult.recordset[i].ip_vch) == -1 &&
            global.failedArr.indexOf(queryResult.recordset[i].ip_vch) == -1
          ) {
            global.successArr.push(queryResult.recordset[i].ip_vch);
            await sql.query`update opower..dialers set fileMoveResult_int=1 where ip_vch =${queryResult.recordset[i].ip_vch}`;
            console.log("success!" + queryResult.recordset[i].ip_vch);
          }
        } catch (error) {
          console.error(error);
          if (global.failedArr.indexOf(queryResult.recordset[i].ip_vch) == -1) {
            global.failedArr.push(queryResult.recordset[i].ip_vch);
            await sql.query`update opower..dialers set fileMoveResult_int=0 where ip_vch =${queryResult.recordset[i].ip_vch}`;
          }
        }
      }
    }
  }
  global.resultArr.success = successArr;
  global.resultArr.failed = failedArr;
  return global.resultArr;
};

    // utility function that creates a promise that rejects after a certain time
    function timeoutPromise(t, errMsg = "timeout") {
        // create possible error object here to get appropriate stack trace
        let e = new Error(errMsg);
        e.timeout = true;
        return new Promise((resolve, reject) => {
            setTimeout(reject, t, e);
        });
    }

// wrap a promise with a timeout, pass promise, time in ms and 
// optional timeout error message
function timeout(p, t, errMsg = "timeout") {
    return Promise.race(p, timeoutPromise(t, errMsg));
}

I am using this await function in a for loop in which from a source directory I need to copy some files to multiple network directories, however the problem here with await is that for the directories it is failing it's taking almost a minute to resolve and then gives the control back for the next iteration, is there a way we could stop the current iteration after 5 seconds.


Solution

  • You can add an error timeout to any promise like this:

    // utility function that creates a promise that rejects after a certain time
    function timeoutPromise(t, errMsg = "timeout") {
        // create possible error object here to get appropriate stack trace
        let e = new Error(errMsg);
        e.timeout = true;
        return new Promise((resolve, reject) => {
            setTimeout(reject, t, e);
        });
    }
    
    // wrap a promise with a timeout, pass promise, time in ms and 
    // optional timeout error message
    function timeout(p, t, errMsg = "timeout") {
        return Promise.race([p, timeoutPromise(t, errMsg)]);
    }
    

    The, you would use this with your fs.copy() like this:

    const writeResult = await timeout(fs.copy(...), 5000);
    

    So, then if the fs.copy() is taking more than 5 seconds, the promise you are awaiting will reject and you can catch it in your catch handler and act accordingly. You will be able to see that the error object has a .timeout property.

    The way this works is that the timeout() function creates a race between the promise you passed in and another promise that will reject after your timeout expires. The first one to complete controls the output of Promise.race() and thus controls what you are using await on. If the timeout wins, then the promise will be rejected.