4

Array and loops through but I want to be able to run all of them in parallel instead as I don't want to run one after another.

I basically want to store all endpoint calls status codes, body and time as array and return them as results regardless of there are errors or not in the endpoint.

I'm using Bluebird, how can I use its features to solve this issue?

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
Passionate Engineer
  • 10,034
  • 26
  • 96
  • 168
  • Can you please come up with a [Short, Self Contained, Correct (Compilable), Example](http://sscce.org/)? – thefourtheye Jan 27 '15 at 06:46
  • WTH is `getComponentStatuses(componentsToCheck)[0]` supposed to do? Why do you build an array at all if you only care for the first? Btw, your requests already *are* running in parallel. – Bergi Jan 27 '15 at 06:56
  • @Bergi thanks for this. I'm using [0] because I'm getting this error if not using it: `Object [object Promise],[object Promise],[object Promise] has no method 'then'` which is `InternalError` – Passionate Engineer Jan 27 '15 at 07:14
  • @thefourtheye I had to show the entire script codebase to allow understanding of exactly what's going on behind the scenes. – Passionate Engineer Jan 27 '15 at 07:18
  • @Bergi what do you mean it's already running in parallel? – Passionate Engineer Jan 27 '15 at 07:18
  • @PassionateDeveloper: Well, you start all these requests without waiting for each other. However, you are only looking at the result of the first request? – Bergi Jan 27 '15 at 07:34
  • @Bergi when I pass in without `[0]` I get above error which is `Object [object Promise],[object Promise],[object Promise] has no method 'then'` this happens at the calling function which is `check` under `module.exports` – Passionate Engineer Jan 27 '15 at 07:38
  • Yes, because you have an array of promises. But if you want all results, not only that of the first, you'll need to use [`Promise.all`](https://github.com/petkaantonov/bluebird/blob/master/API.md#all---promise) – Bergi Jan 27 '15 at 07:49

4 Answers4

6

You can use Promise.map with .bind:

function getComponentStatuses(componentsToCheck) {
    return Promise.map(componentsToCheck, function() {
        var start = Date.now();
        return getAsync({
            url: component.endpoint,
            timeout: component.timeout
        })
        .bind({
             name: component.name,
             status: null,
             body: null,
             time: null
        })
        .spread(function(response, body){
            Logger.info('GET took ' + end + 'ms.');
            this.status = response.statusCode;
            this.body = body;
            return this;
        })
        .catch(function(e) { return this; })
        .finally(function() { this.time = Date.now() - start; })
    });
}

Note that your timing method is incorrect because the http agent might throttle requests.

Esailija
  • 138,174
  • 23
  • 272
  • 326
  • That returned status and body null for all results. Is there something I need to change? – Passionate Engineer Jan 27 '15 at 11:08
  • @PassionateDeveloper that means the spread callback was not called... did you see any "GET took ...." logs ? I think there might be a error which is swallowed by the `.catch` – Esailija Jan 27 '15 at 12:51
  • Hi Esailija, yes since this is a healthcheck there are also endpoints at times would result in connection errors. Is there a way we don't allow `.catch` to swallow? I understand `.settle` allows me to do this but I cannot get time correct with each call as it is duplicated instead – Passionate Engineer Jan 27 '15 at 13:03
  • @PassionateDeveloper In the OP you said you want to swallow all errors, now it depends what kind of errors you want to cause the failure of the entire thing and what other kinds of errors you want to ignore... simply changing `.catch` to `.error` will only catch operational errors and let programming errors such as TypeErrors pass through which will fail the map and by default write the error to stderr if you are not handling the error somewhere else – Esailija Jan 27 '15 at 13:27
4

Bluebird supports multiple concurrent Promises.

See the reference at: https://github.com/petkaantonov/bluebird/blob/master/API.md#promisejoinpromisethenablevalue-promises-function-handler---promise

There are two ways to do it:

.all() - good for a dynamic number of promises

.join() - good for a fixed number of promises and as for Bluebird's documentation, it supplies a better performance than .all() method.

From bluebird's documentation:

 var Promise = require("bluebird");
 var join = Promise.join;

join(getPictures(), getComments(), getTweets(),
function(pictures, comments, tweets) {
console.log("in total: " + pictures.length + comments.length + tweets.length);
});
0

Found the solution.

Use .settle

Passionate Engineer
  • 10,034
  • 26
  • 96
  • 168
-1

I use q Promise Maybe help

return q.all([function or value1, function or value 2, ......])
.spread(function (result1, result2, ....) {
   // do somethine
})

............

Phong Dao
  • 139
  • 1
  • 1
  • 14