0

I am new to using promises with bluebird. I am trying to resolve a promise when the status response is changed to "success" from the api. Below is my code:

exports.getdata(taskCreation, headers) {
  var deferred = Promise.pending();

  var headers = {
    "Authorization": "Secret xxxxxxxxxxxxxxxxx"
  };

  while (true) {
    request.get({
      url: "https://dragon.stupeflix.com/v2/status",
      qs: {
        tasks: taskCreation[0]["key"]
      },
      headers: headers,
      json: true
    }, function (error, httpObj, taskStatusAndResult) {
      if (!error && httpObj.statusCode == 200) {
        console.log(taskStatusAndResult[0]["status"]); //contains either "queued", "executing", "success", or "error"
        if (taskStatusAndResult[0]["status"] == "success")
          deferred.resolve(taskStatusAndResult);

      } else {
        deferred.reject(error);
      }
    })
  }
        return deferred.promise;
}

api takes few seconds to process video,generate videourl and give status as "success".Until then i want to repeatedly keep calling the api,and resolve the promise only if the status is "success". My code with an infinite while loop do not work. Any suggestion on how to achieve this requirement in the best possible way.

Nithish Reddy J
  • 155
  • 3
  • 16

2 Answers2

2

You should always promisify at the lowest possible level, so that you can use promises for everything else.

function makeRequest() {
  return new Promise(function(resolve, reject) {
    request.get({
      url: "https://dragon.stupeflix.com/v2/status",
      qs: {
        tasks: taskCreation[0]["key"]
      },
      headers: {
        "Authorization": "Secret xxxxxxxxxxxxxxxxx"
      },
      json: true
    }, function (error, httpObj, taskStatusAndResult) {
      if (error) reject(error);
      else if (httpObj.statusCode != 200) reject(httpObj); // or so
      else resolve(taskStatusAndResult);
    });
  });
}

Now we can use promise syntax to encode your application usecase, in this case a recursive algorithm that retries the request until it gets a success:

function getData(taskCreation, headers) {
  return makeRequest(taskCreation, headers).then(function(taskStatusAndResult) {
    if (taskStatusAndResult[0]["status"] == "success")
      return taskStatusAndResult;
    else
      return getData(taskCreation, headers); // do it again
  });
}
exports.getdata = getData;
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

You cannot use a while() loop with an async operation. It will just start a zillion API calls before ANY of them have completed. Instead, you have to sequence things. Make one API call. When you get the result, decide in that result handler what to do next.

Also, you were not doing anything with the promise you were creating so I've decided to return the promise from your function.

And, your exports.getData declaration was not a correct function declaration.


Here's one idea where you return a promise and the promise is resolved if you eventually find the "success" status and rejected if an error condition occurs.

This implements the following logic:

  1. Make an API call. When you get the response, do one of four things.
  2. If the response was an error, reject the promise with that error
  3. If the response was success, resolve the promise with the result
  4. If the response was not an error, but not success yet and you've exceeded a max number of retries, then reject with max retries
  5. If the response was not an error, but not success yet and you've not exceeded a max number of retries, then try again
  6. Return a promise from the function so the caller can just use .then() on the promise to get the result or error from the operation

Here's the code:

exports.getdata = function (taskCreation, headers) {
    var headers = {"Authorization": "Secret xxxxxxxxxxxxxxxxx"};
    var cntr = 0;
    var maxRetries = 20;

    return new Promise(function (resolve, reject) {
        function next() {
            ++cntr;
            request.get({
                url: "https://dragon.stupeflix.com/v2/status",
                qs: {tasks: taskCreation[0]["key"]},
                headers: headers,
                json: true
            }, function (error, httpObj, taskStatusAndResult) {
                if (!error && httpObj.statusCode == 200) {
                    console.log(taskStatusAndResult[0]["status"]); //contains either "queued", "executing", "success", or "error"
                    if (taskStatusAndResult[0]["status"] === "success") {
                        // found success to resolve the promise
                        resolve(taskStatusAndResult);
                    } else {
                        // if not "success" yet, then try again
                        if (cntr > maxRetries) {
                            reject(new Error("max retries exceeded"));
                        } else {
                            // try again
                            next();
                        }
                    }
                } else {
                    // got some kind of error here, so stop further processing
                    reject(error);
                }
            })
        }
        // start the first request
        next();
    });
}
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Thank you jfriend00. Your approach seems to be the right way. I will try it. – Nithish Reddy J Aug 05 '15 at 06:32
  • Why not do the recursion with promises? – Bergi Aug 05 '15 at 06:38
  • @Bergi - Lots of ways to approach this one. I could ask you why you didn't promisify the `request.get()` function. There are probably 20 different ways to do this. I kept my answer closer to the OP's original code and thought it was important to implement a retry counter too. – jfriend00 Aug 05 '15 at 06:41
  • @jfriend00: Uh, I did? See my `makeRequest` function :-) – Bergi Aug 05 '15 at 06:41
  • @Bergi - Yours is one approach. Mine is another. There are at least 20 others and the dividing line between promise code and non-promise code can be put in different places. I chose to keep closer to the OP's original code and to implement a retry counter and I kept my use of promises simpler for someone who is likely newish to promises. I won't offer an opinion on one better than the other - just different ways to slice/dice the problem. – jfriend00 Aug 05 '15 at 06:44