Redis PubSub with PHP and Node.JS

Redis get an excellent Publish/Subscribe event system, which can be pretty usefull in a mixed system using PHP and Node.JS.

I will show here a basic example of redis PubSub using Node.JS and PHP : PHP will send an event and Node.JS will check this event to do stuff from that.

First step

For this tutorial, you will need :

Basic idea

In this configuration, imagine an existing chat system done with only PHP, the PHP got few ajax requests :

  • start chat
  • stop chat
  • publish message

The start chat will send previous message (if there is), and start a long polling request to server side PHP, everytime there is a new message, the long polling recieve answer and restart. The stop chat will of course stop this long polling. And publish message will send a message to PHP system (which will cause start system to get the message and start again).
This is how is done many chat system using only PHP. But this system is not the best, the long polling use too much server.

Node.JS with socket.io provide (not in all case) a webSocket interface to work with, wich is extremely good for server performance.

The idea behind this tutorial is to show a basic example using redis to remove the long polling part from PHP and transfert it to Node.JS. In this case you will only modify few request to get it working, and keep the already-working PHP system.

Using Redis

Redis got a PubSub functionality (publish/subscribe), we will use it in this way :
The long polling part is now on Node.JS side (wich is now not long polling but websocket), PHP keep everything else (user login, start chat, stop chat, send message), the start and stop will not do long polling, just send event to Node.JS.
So PHP will only publish event to Redis, while Node.JS will subscribe to channel to perform actions related.

Basic usage in PHP

For this example, i show the most basic example possible, do what you want with to improve you PHP system with Node.JS (i will not show a fully working example of chat system).
The purpose is to send an event from PHP to redis, and catch this event in Node.JS.

First of all, you need on PHP side Predis. Copy thoose files on your PHP server side, no need to configure anything else. Basically it’s classes for using redis instance. We use here the basic redis configuration on localhost and port 6379 :

<?php
//First we load the Predis autoloader
require(dirname(__FILE__)."/Predis/Autoloader.php");
//Register all classes
Predis\Autoloader::register();

//Now we can start creating a redis client to publish event
$redis = new Predis\Client(array(
	"scheme" => "tcp",
	"host" => "127.0.0.1",
	"port" => 6379
));

//Now we got redis client connected, we can publish event (send event)
$redis->publish("the_channel", "this is a test");
?>

With this extremely easy and basic example, everytime somebody will access this page, it will publish and event on channel « the_channel » with content « this is a test ». Of course, you can send JSON, XML, what you want, wich can be pretty helpfull for Node.JS (especially JSON)

All we do now, is to put a Node.JS running in background, waiting for Redis to catch this event.

Before doing that, be sure you get the redis client : « npm install redis » which will be used here by Node.JS to connect to redis server.

var app         = require("http").createServer(handler),
	fs      = require("fs"),
	redis   = require("redis");

app.listen(7070);


//You can specify port and host : redis.createClient(PORT, HOST, options)
var clientSusbcribe = redis.createClient();

clientSusbcribe.subscribe("the_channel");

clientSusbcribe.on("message", function(channel, message){
	console.log("client channel recieve from channel : %s, the message : %s", channel, message);
});


//On client incomming, we send back index.html
function handler(req, res){
	fs.readFile(__dirname + "/index.html", function(err, data){
		if(err){
			res.writeHead(500);
			return res.end("Error loading index.html");
		}else{
			res.writeHead(200);
			res.end(data);
		}
	});
}

That’s almost done, nothing more to do. Feel free to combine with redis tuto for session sharing, and you should now have a fully working link between PHP and Node.JS…

Here is a small screenshot of this small code :
redis PubSub using PHP and Node.JS

Be carefull, don’t forget Node.JS only listen « the_channel » to perform this, if you change channel on PHP you should do the same on Node.JS. Don’t forget also you can have many channel for many event type, which can be pretty helpfull. The clientSubscribe can handle many channel if needed (better to keep only one client for all channel)

Publicités

8 Commentaires

  1. mark

    hello i am trying to use your code but i am getting the following error :
    events.js:66
    throw arguments[1]; // Unhandled ‘error’ event
    ^
    Error: Redis connection to 127.0.0.1:6379 failed – connect ECONNREFUSED
    at RedisClient.on_error (/opt/lampp/htdocs/nodejs/node_modules/redis/index.js:140:24)
    at Socket. (/opt/lampp/htdocs/nodejs/node_modules/redis/index.js:74:14)
    at Socket.EventEmitter.emit (events.js:88:17)
    at Socket._destroy.self.errorEmitted (net.js:327:14)

    • deisss

      It seems your redis instance is not started no ?

      You must start it before running the code, and be carefull with your firewall settings it may interfer with the link you are trying to create…

  2. JB

    Where can we download the code?

  3. anonymouse

    Hi you can also check out reactphp its pretty decent and it does asynchronous io just like node

  4. Hello there…I found this very useful – do you have any tutorials on how to make node emmit message only to a specific user that is logged in to a site that is powered by PHP? I looked at the socket ID or something that I can use to identify which user to send a message too but wondering if you have a tutorial

    • deisss

      As far as I know you need to do a custom code for that, so no there is no easy solution handle this…

      • Thank you for the response. I got a system working that is working great. I do have one problem the PHP Predis publish method that that you use above it calls or publishes to all the clients connected to the server – how do I only publish to one client from this PHP method? Or is that not possible from Predis?

        Thanks

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :