How to use redis PUBLISH/SUBSCRIBE with nodejs to notify clients when data values change?


Question

I'm writing an event-driven publish/subscribe application with NodeJS and Redis. I need an example of how to notify web clients when the data values in Redis change.

1
95
10/21/2011 4:23:14 PM

Accepted Answer

OLD only use a reference

Dependencies

uses express, socket.io, node_redis and last but not least the sample code from media fire.

Install node.js+npm(as non root)

First you should(if you have not done this yet) install node.js+npm in 30 seconds (the right way because you should NOT run npm as root):

echo 'export PATH=$HOME/local/bin:$PATH' >> ~/.bashrc
. ~/.bashrc
mkdir ~/local
mkdir ~/node-latest-install
cd ~/node-latest-install
curl http://nodejs.org/dist/node-latest.tar.gz | tar xz --strip-components=1
./configure --prefix=~/local
make install # ok, fine, this step probably takes more than 30 seconds...
curl http://npmjs.org/install.sh | sh

Install dependencies

After you installed node+npm you should install dependencies by issuing:

npm install express
npm install socket.io
npm install hiredis redis # hiredis to use c binding for redis => FAST :)

Download sample

You can download complete sample from mediafire.

Unzip package

unzip pbsb.zip # can also do via graphical interface if you prefer.

What's inside zip

./app.js

const PORT = 3000;
const HOST = 'localhost';

var express = require('express');

var app = module.exports = express.createServer();

app.use(express.staticProvider(__dirname + '/public'));

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

const io = require('socket.io');

if (!module.parent) {
    app.listen(PORT, HOST);
    console.log("Express server listening on port %d", app.address().port)

    const socket  = io.listen(app);

    socket.on('connection', function(client) {
        const subscribe = redis.createClient();
        subscribe.subscribe('pubsub'); //    listen to messages from channel pubsub

        subscribe.on("message", function(channel, message) {
            client.send(message);
        });

        client.on('message', function(msg) {
        });

        client.on('disconnect', function() {
            subscribe.quit();
        });
    });
}

./public/index.html

<html>
<head>
    <title>PubSub</title>
    <script src="/socket.io/socket.io.js"></script>
    <script src="/javascripts/jquery-1.4.3.min.js"></script>
</head>
<body>
    <div id="content"></div>
    <script>    
        $(document).ready(function() {
            var socket = new io.Socket('localhost', {port: 3000, rememberTransport: false/*, transports: ['xhr-polling']*/});
            var content = $('#content');

            socket.on('connect', function() {
            });

            socket.on('message', function(message){
                content.prepend(message + '<br />');
            }) ;

            socket.on('disconnect', function() {
                console.log('disconnected');
                content.html("<b>Disconnected!</b>");
            });

            socket.connect();
        });
    </script>
</body>
</html>

Start server

cd pbsb    
node app.js

Start browser

Best if you start google chrome(because of websockets support, but not necessary). Visit http://localhost:3000 to see sample(in the beginning you don't see anything but PubSub as title).

But on publish to channel pubsub you should see a message. Below we publish "Hello world!" to the browser.

From ./redis-cli

publish pubsub "Hello world!"
122
3/27/2013 2:41:15 PM

here's a simplified example without as many dependencies. You do still need to npm install hiredis redis

The node JavaScript:

var redis = require("redis"),
    client = redis.createClient();

client.subscribe("pubsub");
client.on("message", function(channel, message){
  console.log(channel + ": " + message);
});

...put that in a pubsub.js file and run node pubsub.js

in redis-cli:

redis> publish pubsub "Hello Wonky!"
(integer) 1

which should display: pubsub: Hello Wonky! in the terminal running node! Congrats!

Additional 4/23/2013: I also want to make note that when a client subscribes to a pub/sub channel it goes into subscriber mode and is limited to subscriber commands. You'll just need to create additional instances of redis clients. client1 = redis.createClient(), client2 = redis.createClient() so one can be in subscriber mode and the other can issue regular DB commands.


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon