1

I am using Redis in Node.js and when deployed on live server it started to crash with below error message:

The no of requests are more per second.

at Object.replyToObject [as reply_to_object] (/home/ubuntu/webservices/node_modules/redis/lib/utils.js:7:15)
at RedisClient.handle_reply (/home/ubuntu/webservices/node_modules/redis/index.js:319:23)
at multi_callback (/home/ubuntu/webservices/node_modules/redis/lib/multi.js:79:43)
at Command.callback (/home/ubuntu/webservices/node_modules/redis/lib/multi.js:116:9)
at normal_reply (/home/ubuntu/webservices/node_modules/redis/index.js:726:21)
at RedisClient.return_reply (/home/ubuntu/webservices/node_modules/redis/index.js:824:9)
at JavascriptRedisParser.returnReply (/home/ubuntu/webservices/node_modules/redis/index.js:192:18)
at JavascriptRedisParser.execute (/home/ubuntu/webservices/node_modules/redis/node_modules/redis-parser/lib/parser.js:553:10)
Socket.<anonymous> (/home/ubuntu/webservices/node_modules/redis/index.js:274:27)
emitOne (events.js:116:13)
Socket.emit (events.js:211:7)
addChunk (_stream_readable.js:263:12)
readableAddChunk (_stream_readable.js:250:11)
at Socket.Readable.push (_stream_readable.js:208:10)
at TCP.onread (net.js:594:20)

I have written common code to open and close the Redis connections and try to reuse connections. (not sure is it correct way of reusing it).

I am using Redis "^2.7.1" and installed Redis locally on Ubuntu.

I am able to enter Redis console and see the keys stored. But not sure why its giving the above error messages very frequently. I am using pm2 module so it restarts once it crashes.

Below is Redis Code in Node.js

var Promise = require('bluebird');
var Redis = Promise.promisifyAll(require('redis'));

// Global (Avoids Duplicate Connections)
var redisClient = null;
var redisMultiClient = null;

// Make the below functions as private
function openRedisConnection() {
    if (redisClient && redisClient.connected)
        return redisClient;

    if (redisClient)
        redisClient.end(); // End and open once more

    redisClient = Redis.createClient(6379,process.env.REDIS_URL);
    redisClient.selected_db = 1;
    return redisClient;
}

function openMultiRedisConnection() {
    if (redisMultiClient && redisMultiClient._client.connected) {
        redisMultiClient._client.selected_db = 0;
        return redisMultiClient;
    }

    if (redisMultiClient)
        redisMultiClient.quit(); // End and open once more

    redisMultiClient = Redis.createClient(6379,process.env.REDIS_URL).multi();
    redisMultiClient._client.selected_db = 0;
    return redisMultiClient;
}

function getExpiryTime(key) {
    return 120; // testing
}


module.exports = {
    /**
     * Get Key-Value Pair
     */
    getRedisValue: function (keys) {
        return openRedisConnection().mgetAsync(keys);
    },
    /**
     * Set Key-Value Pair
     */
    setRedisValue: function (key, value) {
        return openRedisConnection()
            .setAsync(key, value, 'EX', getExpiryTime(key))
            .then(function (result) {
                return Promise.resolve(result);
            });
    },

    getV2MultiRedisValue: function (keyList) {
        let redisMultiClientObj = openMultiRedisConnection();
        redisMultiClientObj._client.selected_db = 2;

        redisMultiClientObj.hgetallAsync(keyList);

        return redisMultiClientObj.execAsync()
            .then(function (results) {
                return Promise.resolve(results);
            });
    },

    setV2MultiRedisValue: function (key, redisList) {
        let expiryTime = getExpiryTime(key);
        let redisMultiClientObj = openMultiRedisConnection();
        redisMultiClientObj._client.selected_db = 2;

        for (let item of redisList) {
            redisMultiClientObj.hmsetAsync(item.key, item.value);
            redisMultiClientObj.expireAsync(item.key, expiryTime);
        }
        return redisMultiClientObj.execAsync()
        .then(function (results) {
            return Promise.resolve(results);
        });
    }
};

1 Answer 1

2

client.multi([commands]) doen't open multi connections, just pointing out because function openMultiRedisConnection is misleading.

You use mulit wrong, per reference

client.multi([commands])

MULTI commands are queued up until an EXEC is issued, and then all commands are run atomically by Redis. The interface in node_redis is to return an individual Multi object by calling client.multi(). If any command fails to queue, all commands are rolled back and none is going to be executed (For further information look at transactions).

Multi returns an individual Object and its not very good to use it again after .exec is called.

I don't know why you need more that one database but you are changing database with selected_db and on a global client variable and this is BAD! and could cause many problems!(data inconsistency, conflict, etc). You can use client.select(callback) to changed database but again it seems like a bad idea.

There is no reason for this part of code its exactly the same as not doing that.

 .then(function (result) {
    return Promise.resolve(result);
  });

You should be ok with only one database.

   var Promise = require('bluebird');
var Redis = Promise.promisifyAll(require('redis'));

// Global (Avoids Duplicate Connections)
var redisClient = [];


// Make the below functions as private
function openRedisConnection( {
    if (redisClient && redisClient.connected)
        return redisClient;

    if (redisClient)
        redisClient.end(); // End and open once more

    redisClient = Redis.createClient(6379,process.env.REDIS_URL,{"db":1});

    return redisClient;
}


function getExpiryTime(key) {
    return 120; // testing
}


module.exports = {
    /**
     * Get Key-Value Pair
     */
    getRedisValue: function (keys) {
        return openRedisConnection().mgetAsync(keys);
    },
    /**
     * Set Key-Value Pair
     */
    setRedisValue: function (key, value) {
        return openRedisConnection()
            .setAsync(key, value, 'EX', getExpiryTime(key));

    },

    getV2MultiRedisValue: function (keyList) {

         let redisClient = openRedisConnection();

        //no need to open multi here....
        let multi = redisClient.multi();

        multi.hgetallAsync(keyList);

        return multi.execAsync();

    },

    setV2MultiRedisValue: function (key, redisList) {
        let expiryTime = getExpiryTime(key);
        let redisClient = openRedisConnection();

        let multi = redisClient.multi();

        for (let item of redisList) {
            multi.hmsetAsync(item.key, item.value);
            multi.expireAsync(item.key, expiryTime);
        }

        return multi.execAsync();

    }
};
Sign up to request clarification or add additional context in comments.

5 Comments

thanks for answer.. 1 .then(function (result) { return Promise.resolve(result); }); actually before the promise is resolved there is some business logic which is removed for clarity so this is ok.. 2 different db's need to check if I can merge. 3 Multi concept let me implement and get back to you asap
//no need to open multi here.... you have mentioned this comment in getV2MultiRedisValue function and saying let multi = redisClient.multi(); is this correct ? just getting confused
multi is used to do que and run multiple commands. Since you only do hgetallAsync which is only one command there is no need for multi
Redis is commonly used for cached data and not complex "business" logic. What exactly are you trying to merge... Maybe you have some logic that can run differently?
thanks i checked for almost 5 days monitoring the server no crashes happened. Your code worked.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.