Search code examples
javascriptnode.jsnode-redisredis-sentinel

How to pass JS Object to its own event parameter in redis - sentinal on connect event


In redis sentinel client program - first program, when i keep the redis sentinel object to be created and it works fine to set the KEY . But when you observe the second program , client.on('connect', runSample(client)); I am passing the client object ( redis sentinel client ), its on connect parameter runSample. For this I am getting the following error ..

Error Details

https://github.com/DocuSignDev/node-redis-sentinel-client/blob/master/index.js

 RedisSentinelClient.prototype.send_command  undefined
  /node_modules/redis-sentinel-client/index.js:293
  return client.send_command.apply(client, arguments);
           ^
  TypeError: Cannot read property 'send_command' of undefined
at RedisSentinelClient.send_command (/node_modules/redis-sentinel-client/index.js:293:16)
at RedisSentinelClient.(anonymous function).RedisSentinelClient.(anonymous function) (/node_modules/redis-sentinel-client/index.js:307:23)
at runSample (/msg/lb4.expire.onefile.2m.notworking.js:25:13)
at init (/msg/lb4.expire.onefile.2m.notworking.js:16:26)
at Object.<anonymous> (/msg/lb4.expire.onefile.2m.notworking.js:75:1)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
RajRajen:pubsub.local rajrajen$

First working program..

'use strict';
 var client = getRedisSentinelObject();
 client.on('error', function(err) {
   console.log('Error ' + err);
 });

client.on('connect', runSample);

function runSample() {

   var allStrings = '{abc:123}';


   client.get(allStrings, function(err, reply) {
      if (reply) {
        console.log('Key is ' + reply.toString());
        client.ttl(allStrings, writeTTL);
    } else {
        console.log('string key expired or not set before!');
        // Set a value
        client.set(allStrings, allStrings);
        // Expire in 3 seconds
        client.expire(allStrings, 3);
    }
    client.quit();
    });
 }

 function getRedisSentinelObject() {
   
   var redisSentinelHost = process.env.REDIS_SENTINEL_SERVICE_HOST;
   var redisSentinelPort = process.env.REDIS_SENTINEL_SERVICE_PORT;

   var options = {
      'master_debug': false
    };


    var redisSentinelMasterDebug = process.env.REDIS_SENTINEL_MASTER_DEBUG;


if (typeof redisSentinelMasterDebug !== "undefined") {
    if (redisSentinelMasterDebug === "true") {
        options.master_debug = true;
    }
}

console.log('redisSentinelHost ', redisSentinelHost, 'redisSentinelPort ', redisSentinelPort);

var RedisSentinel = require('redis-sentinel-client');
var sentinelClient = RedisSentinel.createClient(redisSentinelPort, redisSentinelHost, options);
console.log('sentinelClient ', sentinelClient);

return sentinelClient;
}

function writeTTL(err, data) {
    console.log('I live for this long yet: ', data);
}

Second program, that is not working

 'use strict';

  function init() {

var client = getRedisSentinelObject();


client.on('error', function(err) {
    console.log('Error ' + err);
});

client.on('connect', runSample(client));

}

function runSample(client1) {


var allStrings = '{abc:123}';


client1.get(allStrings, function(err, reply) {
    if (reply) {
        console.log('Key is ' , reply.toString());
        client1.ttl(allStrings, writeTTL);
    } else {
        console.log('string key expired or not set before!');
        // Set a value
        client1.set(allStrings, allStrings);
        // Expire in 3 seconds
        client1.expire(allStrings, 2);
    }
   // client1.quit();
});


}

 function getRedisSentinelObject() {

var redisSentinelHost = process.env.REDIS_SENTINEL_SERVICE_HOST;
var redisSentinelPort = process.env.REDIS_SENTINEL_SERVICE_PORT;

var options = {
    'master_debug': false
};


var redisSentinelMasterDebug = process.env.REDIS_SENTINEL_MASTER_DEBUG;

if (typeof redisSentinelMasterDebug !== "undefined") {
    if (redisSentinelMasterDebug === "true") {
        options.master_debug = true;
    }
}

console.log('redisSentinelHost ', redisSentinelHost, 'redisSentinelPort ', redisSentinelPort);

var RedisSentinel = require('redis-sentinel-client');
var sentinelClient = RedisSentinel.createClient(redisSentinelPort, redisSentinelHost, options);
console.log('sentinelClient ', sentinelClient);

return sentinelClient;
}

function writeTTL(err, data) {
console.log('I live for this long yet: ', data);
}

init();

Thanks


Solution

  • The problem

    In example 1 you have the line:

    client.on('connect', runSample);
    

    This line attaches a function to be run when the client connects. All is good. Please note that the function is not run until the client connects.

    In example 2, the same line looks like this:

    client.on('connect', runSample(client));
    

    In this line, the runSample method is executed immediately. The result of this function call (in this case undefined) is then passed into client.on. So if we do a little bit of the evaluation by hand here, the javascript boils down to:

    client.on('connect', undefined);
    

    This fails because you're telling redis, "When you connect, nothing".

    The easy fix

    The easiest way to fix this is to use a closure (a function that absorbs it's scope). This is most likely what you meant to do.

    client.on('connect', function () {
        runSample(client)
    });
    

    The more complicated fix

    If you wanted to make things a bit more complicated, you could make a function like this:

    function buildRunner (client) {
       return function runTests () {
           var allStrings = '{abc:123}';
    
    
           client.get(allStrings, function(err, reply) {
               if (reply) {
                   console.log('Key is ' + reply.toString());
                   client.ttl(allStrings, writeTTL);
               } else {
                   console.log('string key expired or not set before!');
                   // Set a value
                   client.set(allStrings, allStrings);
                   // Expire in 3 seconds
                   client.expire(allStrings, 3);
               }
               client.quit();
           });
       }
    }
    

    And use it like:

    client.on('connect', buildRunner(client));
    

    Please note that buildRunner will be executed immediately, just like before. The difference is that buildRunner returns a function that gets passed into client.on. If we do some evaluation by hand again, we get:

    client.on('connect', function runTests () { ... })
                      // ^ runTests is holding on to an internal copy of `client` because
                      //   `client` existed back when we built runTests
                      //   up in `buildRunner`