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
How to Have Jquery Restrict File Types on Upload
Paste an Image from Clipboard Using JavaScript
How to Test If a Letter in a String Is Uppercase or Lowercase Using JavaScript
React - Getting a Component from a Dom Element for Debugging
How to Detect with JavaScript/Jquery If the User Is Currently Active on the Page
Angularjs: How to Run Additional Code After Angularjs Has Rendered a Template
Using Lodash .Groupby. How to Add Your Own Keys for Grouped Output
How to Prevent Simultaneous Logins of the Same User with Firebase
Angularjs - How to Get an Ngrepeat Filtered Result Reference
Ipad/iPhone Browser Crashing When Loading Images in JavaScript
Calling Method Using JavaScript Prototype
Find Day Difference Between Two Dates (Excluding Weekend Days)
Property 'Value' Does Not Exist on Type Eventtarget in Typescript
What Does Variable Declaration with Multiple Comma Separated Values Mean (E.G. Var a = B,C,D;)
Convert a Directory Structure in the Filesystem to JSON with Node.Js