Sharath
Sharath

Reputation: 2428

Redis error in node.js

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);
        });
    }
};

Upvotes: 1

Views: 5807

Answers (1)

Stamos
Stamos

Reputation: 3998

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();

    }
};

Upvotes: 2

Related Questions