How to Use Redis Publish/Subscribe with Nodejs to Notify Clients When Data Values Change

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

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!"

Publish subscribe with nodejs and redis(node_redis)

That seems like a pretty reasonable solution to me. What don't you like about it?

Something to keep in mind is that you can have multiple subscriptions on each Redis connection. This might end up complicating your logic, which is the opposite of what you are asking for. However, at scale this might be necessary. Each Redis connection is relatively inexpensive, but it does require a file descriptor and some memory.

NodeJS Redis Listener

Yes, it is possible. You need to use Redis Keyspace Notifications.

See especially the Events generated by different commands part. You probably want to be notified when the SET command is used :

var redis = require('redis');
var client_redis = redis.createClient();

// enable notify-keyspace-events for all kind of events (can be refined)
client_redis.config('set','notify-keyspace-events','KEA');

client_redis.subscribe('__keyevent@0__:set');
// you can target a specific key with a second parameter
// example, client_redis.subscribe('__keyevent@0__:set', 'mykey')

client_redis.on('message', function(channel, key) {
// do what you want when a value is updated
});

Redis Keyspace Notifications subscription for field&value

You can use RedisGears to process keyspace notification and get both key and value.

You can write your processing code in python and register it in Redis.
e.g. Capture each keyspace event and store to a Stream

GearsBuilder() \
.foreach(lambda x: execute('XADD', "notifications-stream", '*', *sum([[k,v] for k,v in x.items()],[]))) \
.register(prefix="person:*", eventTypes=['hset', 'hmset'], mode='sync')

You can read more about this example here: https://oss.redis.com/redisgears/examples.html#reliable-keyspace-notification



Related Topics



Leave a reply



Submit