Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

node.js redis and how to use promise when using a module

I have an Express route like this in an node server (file is required):

var redis = require('../modules/redis');

module.exports = function (app) {

var redisClient = redis.init();


app.post('/auth/ticket', cors(), function (req, res) {


    var hashes = ['hash1','hash2', 'hash3'];

    var candidates = [];  // An array to collect valid hashes
    var key;  
    // to check each hash against a RedisDB I use a For Loop
    for (key in hashes) {
        var hash = hashes[key];
        console.log("Hash " + hash + "  will be proofed now:");
       //now I try to collect the valid hashes in the candidates array
       if (redisClient.exists(hash) === 1) candidates.push(hash);
    }
    console.log(JSON.stringify(candidates));
});
};

Now here is the code of my module which shall manage all the redis requests:

exports.init = function () {
Redis = exports.Redis = function () {
    var promiseFactory = require("q").Promise,
        redis = require('promise-redis')(promiseFactory);

    this.client = redis.createClient();
    this.client.on('error', function (err) {
        console.log('redis error – ' + client.host + ':' + client.port + ' – ' + err);
    });

Redis.prototype.exists = function (key) {
    this.client.exists(key, function (err, data) {
       return data === 1 ? true : false;
    });
};

return new Redis();
};

So what I experience is that the module is able to console.log the results properly. If a hash is valid, it returns true and otherwise false. This works as expected. Problem is, that the for-loop continuous the execution without fetching getting the results. I think this is caused by race-conditions.

As you can see, I have started to workout something there with the use of Q and promise-redis in the top of my code:

 var promiseFactory = require("q").Promise,
    redis = require('promise-redis')(promiseFactory);

this.client = redis.createClient();

I like to know, how I make my for-loop (in the Express route) waiting for the results of redisClient.exists(hash) or in other words, to get all valid hashes into my candidates array.

Please help

like image 509
gwinger Avatar asked Oct 31 '22 02:10

gwinger


2 Answers

like @brad said, you could use Q.all, it would take an array of promises as input and then return an array of results when all the promises are finished:

there is a mistake in your answer:

Redis.prototype.exists = function (key) {

return this.client.exists(key)      // CHANGED, you still need to return a promise.
    .then(function (reply) {
        console.log("reply " + reply);
        return (reply);
    })
    .catch(console.log);

};

If I understand correctly, what you want is something like

exports.init = function () {
Redis = exports.Redis = function () {
    var Q = require("q"),
        promiseFactory = Q.Promise,
        redis = require('promise-redis')(promiseFactory);

    this.client = redis.createClient();
    this.client.on('error', function (err) {
        console.log('redis error – ' + client.host + ':' + client.port + ' – ' + err);
    });

Redis.prototype.exists = function (key) {
    return this.client.exists(key).then(function (data) {
       return data === 1 ? true : false;
    });
};

Redis.prototype.getActive = function (arry) {
    var self = this;
    return  Q.all(arry.map(self.exists.bind(self))
            ).then(function(res){
                return arry.filter(function(val, idx){ return res[idx];});
            });
};



return new Redis();
};
like image 139
mido Avatar answered Nov 12 '22 18:11

mido


@ mido22: But did you also recognize that I outsourced all the reds functions to the module file (1st Codeblock) which requires the promise-redid and builds a factory for Q. I changed the code inside the module file to:

    Redis.prototype.exists = function (key) {

    this.client.exists(key)
        .then(function (reply) {
            console.log("reply " + reply);
            return (reply);
        })
        .catch(console.log);

    };

and this results correctly like the console.log evidently shows. Your codechange of the for-loop works very well but I think it don't fulfills my needs perfectly. If I could, I would like to have it completely outsourced in to the module file, so that I can use the prototyped method in similar cases from everywhere. Is that possible anyhow? I see, that it would result in having two promise supported functionalities, if I would create an Instance of Redis Client with promise-redid and Q inside the auth/ticket/ router, too. like this:

var Q = require('q'),
promiseFactory = Q.Promise,
redis = require("promise-redis")(promiseFactory),
client;

an then the express route (there are a lot of more routes each in a single file) like in your code.

Do you understand what I mean? Of course your solution will be fine for my needs at all, but a module resolving the job completely could have more elegance if possible so far.

like image 25
gwinger Avatar answered Nov 12 '22 16:11

gwinger