0

I am using promises to retry API requests if they fail. I am using it like so:

var promise = new Promise((resolve, reject) => {
    client.ApiRequest(params, function(data) {
        if (!Array.isArray(data)) {
            console.log("There was an error with the request.");
            reject("Rate Limit Exceeded");
            return;
        }
        ...
        resolve();
    });
});
Utils.retry(promise, 1500);

And then the Utils.retry method is as follows:

static delay(delayMS) {
    return new Promise(function(resolve, reject){
        setTimeout(resolve, delayMS);
    });
}

static retry(operation, delayMS) {
    return operation.catch((err) => {
        console.log(err);
        return Utils.delay(delayMS).then(function(){
            return Utils.retry(operation, delayMS)
        });
    });
}

As you can see, it catches the reject() from the promise and uses delay() to wait before retrying. The code runs, but it seems like once the promise fails once it is constantly stuck in the rejected state.

For instance, when it fails, it delays, and then it retries the promise just to output the same reject message. However, in the first function, it does not print out the "There was an error with the request" message on subsequent retries, so I don't think it's even retrying.

Is there a way to reset this promise state so that it when it retries it executes all of the code in the promise function?

w0f
  • 908
  • 9
  • 23
  • did you write these utility methods? (i.e. do you need to stick to them?) Also, to bluntly answer your the last part of your question, you cannot change state of the promise. Once it's resolved/rejected, it's final. – Govind Rai Dec 18 '17 at 22:38
  • 1
    @GovindRai i wrote them based on a previous answer here that wasn't using promises, but .catch() kept throwing an error on plain functions, so I modified it to run like this. This is the only function using the retry utility function at the moment, so changing it isn't a big deal. – w0f Dec 18 '17 at 22:43
  • A promise is not an operation. It's a result. – Bergi Dec 18 '17 at 23:34
  • Why is your `Utils` a `class`? You'll hardly want to instantiate it, will you? – Bergi Dec 18 '17 at 23:35
  • @Bergi Utils is a group of static functions wrapped into a class for readability/only one module export needed. I don't ever instantiate it; just include it. – w0f Dec 19 '17 at 00:35
  • @w0ffen Then [don't use a `class`](https://stackoverflow.com/q/29893591/1048572)! – Bergi Dec 19 '17 at 01:03
  • @Bergi what would be ideal in this situation then, a constant object of functions? – w0f Dec 19 '17 at 08:01
  • @w0ffen Ideal would be multiple individually exported functions, and a namespace import if you want to have them in an object. – Bergi Dec 19 '17 at 08:05

2 Answers2

1

Don't pass a reference to the original promise. Pass in a new promise each time. Here's how you can do that.

// a function that returns a new promise
var createPromise = function() {
    return new Promise((resolve, reject) => {
        client.ApiRequest(params, function(data) {
            if (!Array.isArray(data)) {
                console.log("There was an error with the request.");
                reject("Rate Limit Exceeded");
                return;
            }
            ...
            resolve();
        });
    });
}    

-

static delay(delayMS) {
    return new Promise(function(resolve, reject){
        setTimeout(resolve, delayMS);
    });
}

static retry(operation, delayMS) {
    return operation().catch((err) => { //invoke the promise function
        console.log(err);
        return Utils.delay(delayMS).then(function(){
            return Utils.retry(operation, delayMS)
        });
    });
}

Utils.retry(promise, 1500);
Govind Rai
  • 14,406
  • 9
  • 72
  • 83
0

It's giving you the same result because your passing the same, already rejected, promise back to your retry handler. You need to create a new promise to give back to the retry handler for this to work.

That means that you probably need to modify the retry handler to accept a promise factory (a function that returns the promise you want), rather than the promise itself. So you might modify your code like this:

// Make function to return this promise instead:
var makePromise = () => {
    return new Promise((resolve, reject) => {
        client.ApiRequest(params, function(data) {
            if (!Array.isArray(data)) {
                console.log("There was an error with the request.");
                reject("Rate Limit Exceeded");
                return;
            }
            ...
            resolve();
        });
    });
};

Utils.retry(makePromise, 1500);

-

static delay(delayMS) {
    return new Promise(function(resolve, reject){
        setTimeout(resolve, delayMS);
    });
}

static retry(operation, delayMS) {
    // Note the () after operation. This function now expects operation
    // to be a function that returns a promise.
    return operation().catch((err) => {
        console.log(err);
        return Utils.delay(delayMS).then(function(){
            return Utils.retry(operation, delayMS)
        });
    });
}
CRice
  • 29,968
  • 4
  • 57
  • 70