Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js: Closing all Redis clients on shutdown

Today, I integrated Redis into my node.js application and am using it as a session store. Basically, upon successful authentication, I store the corresponding user object in Redis.

When I receive http requests after authentication, I attempt to retrieve the user object from Redis using a hash. If the retrieval was successful, that means the user is logged in and the request can be fulfilled.

The act of storing the user object in Redis and the retrieval happen in two different files, so I have one Redis client in each file.

Question 1: Is it ok having two Redis clients, one in each file? Or should I instantiate only one client and use it across all areas of the application?

Question 2: Does the node-redis library provide a method to show a list of connected clients? If it does, I will be able to iterate through the list, and call client.quit() for each of them when the server is shutting down.

By the way, this is how I'm implementing the "graceful shutdown" of the server:

//Gracefully shutdown and perform clean-up when kill signal is received
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);

function cleanup() {
    server.stop(function() {
        //todo: quit all connected redis clients

        console.log('Server stopped.');

        //exit the process
        process.exit();
    });
};
like image 569
shaunlim Avatar asked Jan 03 '14 01:01

shaunlim


2 Answers

In terms of design and performance, it's best to create one client and use it across your application. This is pretty easy to do in node. I'm assuming you're using the redis npm package.

First, create a file named redis.js with the following contents:

const redis = require('redis');

const RedisClient = (function() {
    return redis.createClient();
})();

module.exports = RedisClient

Then, say in a file set.js, you would use it as so:

const client = require('./redis');
client.set('key', 'value');

Then, in your index.js file, you can import it and close the connection on exit:

const client = require('./redis');

process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);

function cleanup() {
    client.quit(function() {
        console.log('Redis client stopped.');
        server.stop(function() {
            console.log('Server stopped.');
            process.exit();
        });
    });
};
like image 136
devshawn Avatar answered Oct 18 '22 09:10

devshawn


Using multiple connections may be required by how the application uses Redis.

For instance, as soon as a connection is used the purpose of listening to a pub/sub channel, then it can only be used for this and nothing else. Per the documentation on SUBSCRIBE:

Once the client enters the subscribed state it is not supposed to issue any other commands, except for additional SUBSCRIBE, PSUBSCRIBE, UNSUBSCRIBE and PUNSUBSCRIBE commands.

So if your application needs to subscribe to channels and use Redis as general value cache, then it needs two clients at a minimum: one for subscribing to channels and one for using Redis as a cache.

There are also Redis commands that are blocking like BLPOP. A busy web server normally replies to multiple requests at once. Suppose that for answering request A the server uses its Redis client to issue a blocking command. Then request B comes and the server needs to answer Redis with a non-blocking command but the client is still waiting for the blocking command issued for request A to finish. Now the response to request B is delayed by another request. This can be avoided by using a different client for the second request.

If you do not use any of the facilities that require more than one connection, then you can and should use just one connection.

If the way you use Redis is such that you need more than one connection, and you just need a list of connections but no sophisticated connection management, you could just create your own factory function: it would call redis.createClient() and save the client before returning it. Then at shutdown time, you could go over the list of saved clients and close them. Unfortunately, node-redis does not provide such functionality built-in.

If you need more sophisticated client management than the factory function described above, then the typical way to manage the multiple connections created is to use a connection pool but node-redis does not provide one. I usually access Redis through Python code so I don't have a recommendation for Node.js libraries, but an npm search shows quite a few candidates.

like image 38
Louis Avatar answered Oct 18 '22 10:10

Louis