Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retry on Javascript.Promise.reject a limited number of times or until success

I have a function say myMainFunction that is called from a client, that in turn calls mypromisified function.

Scenario: mypromisified function can fail intermittently and I need to call this function with a delay (at an exponential increase) until success or until max no of tries reached.

What I have so far

The following code illustrates my scenario and repeats itself until success, but it tries indefinitely and not until certain count is reached

// called once from the client
myMainFuntion();

function rejectDelay(delay, reason) {
   // call main function at a delayed interval until success 
   // but would want to call this only a limited no of times
    setTimeout(() => {
      myMainFuntion(); // calling main function again here but with a delay
    }, delay);
}


function myMainFuntion() {
  var delay = 100;
  var tries = 3;
  tryAsync().catch(rejectDelay.bind(null, delay));
}

function tryAsync() {
  return new Promise(function(resolve, reject) {
    var rand = Math.random();
    console.log(rand);
    if (rand < 0.8) {
      reject(rand);
    } else {
      resolve();
    }
  });

}

while loop inside the rejectDelay would certainly not work as the counter would increment even before the actual function inside setInterval is executed, so am unsure as to how to go about this? so...

I tried promisifying the setInterval something like this knowing it will fail :( as it doesnt decrement the counter, but not sure how to get it right either .

function rejectDelay(delay, maximumTries, reason) {
  return new Promise(function (resolve, reject) {
    console.log(tries + ' remaining');
    if (--maximumTries > 0) {
      setTimeout(function() {
        foo();
      }, 500);
    } 
  });
}
function myMainFunction() {
  var delay = 100;
  var maximumTries = 3;
  tryAsync().catch(rejectDelay.bind(null, delay, maximumTries));
}
like image 831
Jaya Avatar asked Feb 24 '17 02:02

Jaya


1 Answers

Using a couple of helper functions I've used a lot, this becomes very easy

The "helpers"

Promise.wait = (time) => new Promise(resolve => setTimeout(resolve, time || 0));
Promise.retry = (cont, fn, delay) => fn().catch(err => cont > 0 ? Promise.wait(delay).then(() => Promise.retry(cont - 1, fn, delay)) : Promise.reject('failed'));

The code:

function myMainFuntion() {
      var delay = 100;
      var tries = 3;
      Promise.retry(tries, tryAsync, delay);
}

ES5 versions of the helpers

Promise.wait = function (time) {
    return new Promise(function (resolve) {
        return setTimeout(resolve, time || 0);
    });
};
Promise.retry = function (cont, fn, delay) {
    return fn().catch(function (err) {
        return cont > 0 ? Promise.wait(delay).then(function () {
            return Promise.retry(cont - 1, fn, delay);
        }) : Promise.reject('failed');
    });
};
like image 79
Jaromanda X Avatar answered Oct 04 '22 15:10

Jaromanda X