Are all Redis Commands Asynchronous?
Asked Answered
I

2

6

I am new to Redis and Node.JS and have been attempting to use the two together. However I am a little confused by which functions I can use one after the other.

The following code appears to run synchronously, with the database growing in size:

client.dbsize(function(err, numKeys) {
  console.log("DB Size before hashes added" + numKeys);
  return numKeys;
});

for (var i = 0; i < 100; i++) {
  client.hmset(i, "username", "username", "answer", "answer");
  client.zadd('answer', i, i);
};

client.dbsize(function(err, numKeys) {
  console.log("DB Size after hashes added" + numKeys);
  return numKeys;
});

However, when I then try to query the sorted set 'answer' to return an array, this array, 'reply' is not immediately available to other redis functions outside the callback to 'zrevrangebyscore'.

client.zrevrangebyscore('answer', 100, 0, function(err, reply) {
  console.log (reply);
  return reply;
});

For example, a subsequent 'hgetall' function called on reply[1] returns undefined. Should I use all Redis functions (including the hmset and dbsize) in an asynchronous manner with callbacks/client.multi etc. or do some work effectively if used synchronously? All help gratefully received.

Illsuited answered 17/10, 2015 at 12:9 Comment(0)
Z
18

Redis is single-threaded, so the commands on Redis are always executed sequentially. It looks like you might be using an async client for Redis, and that's where the confusion is coming from. Because you have no guarantees on network latency, if you're using an async Redis client, a later call can hit the Redis server before an earlier call and cause the issues you're running into. There's a very good explanation of why Async clients for Redis exist at all here.

All of that said, the important point in your case is that if you want your commands guaranteed to run synchronously, you have a few options:

  1. Use a pipeline in Redis to only have one back-and-forth with the server for all of your commands (probably a good idea anyway, unless you have some need to do something between commands).
  2. Use the async lib, like documented here.
  3. Use a synchronous Redis client. I don't know enough about Node.js to know how viable this is.
Zoubek answered 18/10, 2015 at 23:29 Comment(1)
Thanks for the answer, a big help!Illsuited
G
0

You seem pretty confused when it comes to synchronous and asynchronous code. I'd recommend reading up as much as you can till it "clicks". I'll give an example on what is going wrong and why:

//we're going to fake the redis dbSize function
var dbSize = function(callback){
  //always finishes asynchronously
  console.log("dbsize called");
  setTimeout(callback, 1000);
};

//here we get to your code
dbSize(function(){
  console.log("First callback");
});

console.log("synchronous redis method calls");
//here come the synchronous redis methods, that finish synchronously

dbSize(function(){
  console.log("Second callback");  
});

Now, if you run this code it outputs the following to the console:

"dbsize called"
"synchronous redis method calls"
"dbsize called"
"First callback"
"Second callback"

As you can see the synchronous methods are called, before the asynchronous ones are finished. So, all there is to it is to make sure you call the synchronous methods afterwards, which would be in the first callback, i.e. You have to chain this stuff together. Now this is messy, since it leads you to callback hell:

dbSize(function(){

    console.log("First callback");

    console.log("synchronous redis method calls");
    //here come the synchronous redis methods, that finish synchronously

    dbSize(function(){
      console.log("Second callback");  
    });
})

So, to avoid that it's best to use something like the async lib

async.series([
    function(next){
        dbSize(next);
    },
    function(next){
        console.log("synchronous redis method calls");
        //here come the synchronous redis methods, that finish synchronously
        next();            
    },
    function(next){
        dbSize(next);
    },
], function(){
    console.log('All done!');
})

This will output:

"dbsize called"
"synchronous redis method calls"
"dbsize called"
"All done!"
Gid answered 17/10, 2015 at 12:44 Comment(1)
Thanks for the answer, a big help!Illsuited

© 2022 - 2024 — McMap. All rights reserved.