Comment utiliser redis PUBLISH / SUBSCRIBE avec nodejs pour avertir les clients lorsque les valeurs des données changent?

99

J'écris une application de publication / abonnement basée sur les événements avec NodeJS et Redis. J'ai besoin d'un exemple de la manière d'avertir les clients Web lorsque les valeurs de données dans Redis changent.

guilin 桂林
la source

Réponses:

123

OLD n'utilise qu'une référence

Dépendances

utilise express , socket.io , node_redis et enfin et surtout l' exemple de code de Media Fire.

Installez node.js + npm (en tant que non root)

Tout d'abord, vous devez (si vous ne l'avez pas encore fait) installer node.js + npm en 30 secondes (la bonne façon car vous ne devez PAS exécuter npm en tant que 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

Installer les dépendances

Après avoir installé node + npm, vous devez installer les dépendances en émettant:

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

Télécharger un échantillon

Vous pouvez télécharger un échantillon complet à partir de mediafire .

Décompressez le package

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

Qu'y a-t-il à l'intérieur du 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>

Démarrer le serveur

cd pbsb    
node app.js

Lancer le navigateur

Le mieux si vous démarrez Google Chrome (en raison de la prise en charge des websockets, mais pas nécessaire). Visitez http://localhost:3000pour voir un échantillon (au début, vous ne voyez rien d'autre PubSubque le titre).

Mais sur publishle canal, pubsubvous devriez voir un message. Ci-dessous, nous publions "Hello world!"dans le navigateur.

À partir de ./redis-cli

publish pubsub "Hello world!"
Alfred
la source
pourquoi avez-vous besoin const client = redis.createClient()de la racine de app.js?
Akasha
vous n'avez pas du tout besoin d'utiliser const. var pourrait également être utilisé et peut-être que j'aurais dû le faire à la place car const n'est disponible que dans les nouveaux moteurs javascript. De plus, cette ligne garantit que nous sommes connectés au serveur redis que nous utilisons dans cet exemple.
Alfred
5
L'exemple est très ancien, donc pas à jour avec les derniers modules socket.io/express et peut-être même node.js. J'essaierais de mettre à jour le code. Il existe également un autre énorme problème avec ce code: il ouvre une autre connexion Redis pour chaque utilisateur connecté. Cela ne devrait être activé qu'à la place. Je dois d'abord travailler, mais après cela, j'essaye de mettre à jour le code.
Alfred
1
Très bien. Je pense toujours qu'il y a de la place pour des améliorations que je mettrai en ligne lorsque j'aurai le temps. Mais en ce moment je travaille vraiment dur: $.
Alfred
1
Je pense que subscribe.on devrait être en dehors du bloc socket.on ('connection') pour éviter plusieurs abonnés /
zubinmehta
26

voici un exemple simplifié sans autant de dépendances. Vous avez encore besoin denpm install hiredis redis

Le nœud JavaScript:

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

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

... mettez cela dans un fichier pubsub.js et exécutez node pubsub.js

dans redis-cli:

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

qui devrait afficher: pubsub: Hello Wonky!dans le terminal en cours d'exécution node! Félicitations!

Supplémentaire 23/04/2013: Je tiens également à noter que lorsqu'un client s'abonne à un canal pub / sous, il passe en mode abonné et est limité aux commandes des abonnés. Vous aurez juste besoin de créer des instances supplémentaires de clients redis. client1 = redis.createClient(), client2 = redis.createClient()donc l'un peut être en mode abonné et l'autre peut émettre des commandes DB régulières.

nak
la source
Ici, lorsque nous ajoutons des données au redis, dois-je exécuter publish pubsub pour obtenir une notification d'insertion?
IshaS
1
@IshaS si c'est ce que vous devez faire, oui. Vous devriez également examiner les transactions si vous avez besoin d'exécuter plusieurs commandes de manière atomique: redis.io/commands/exec
nak
@nak Cela a fonctionné comme du charme dans un GO :) Certains utilisateurs peuvent avoir besoin d'installer 'double-end-queue' s'il n'est pas déjà installé.
Manjeet
1
Il convient également de mentionner que si vous souhaitez utiliser des caractères génériques, par exemple, abonnez-vous pour pubsub/*simplement ajouter pà l'exemple: remplacer subscibepar psubscribeet messagepar pmessage.
Liosha Bakoushin le
7

Exemple complet de Redis Pub / Sub ( chat en temps réel avec Hapi.js & Socket.io)

Nous essayions de comprendre Redis Publish / Subscribe (" Pub / Sub ") et tous les exemples existants étaient soit obsolètes, soit trop simples, soit sans tests. Nous avons donc écrit une discussion complète en temps réel à l'aide de l'exemple Hapi.js + Socket.io + Redis Pub / Sub avec des tests de bout en bout !

https://github.com/dwyl/hapi-socketio- redis-chat-example

Le composant Pub / Sub n'est que quelques lignes de code node.js: https://github.com/dwyl/hapi-socketio-redis-chat-example/blob/master/lib/chat.js#L33-L40

Plutôt que de le coller ici ( sans aucun contexte ), nous vous encourageons à vérifier / essayer l' exemple .

Nous avons construit à l'aide Hapi.js mais le chat.jsfichier est découplé de Hapi et peut facilement être utilisé avec un base serveur http Node.js ou exprimer (etc.)

nelsonic
la source
avez-vous cet exemple avec express?
Gixty le
@Gixty nous avons écrit l'exemple en utilisant Hapi.js car tous les autres exemples utilisent Express.js ... comme mentionné dans l'article, il est trivial de le porter sur n'importe quel autre framework Node.js (il suffit de passer dans l'application express / écouteur du code d'initialisation de chat.js) et cela fonctionne exactement de la même manière. ps: si vous êtes nouveau sur Hapi.js voir: github.com/nelsonic/learn-hapi
nelsonic
4

Gérez les erreurs redis pour empêcher nodejs de se fermer. Vous pouvez le faire en écrivant;

subcribe.on("error", function(){
  //Deal with error
})

Je pense que vous obtenez l'exception parce que vous utilisez le même client qui est abonné pour publier des messages. Créez un client distinct pour publier des messages et cela pourrait résoudre votre problème.

Awemo
la source
2

Si vous voulez que cela fonctionne avec socket.io 0.7 ET un serveur Web externe, vous devez changer (en plus du staticProvider -> problème statique):

a) fournir le nom de domaine au lieu de localhost (c.-à-d. var socket = io.connect ('http://my.domain.com:3000');) dans l'index.html

b) changez HOST dans app.js (ie const HOST = 'my.domain.com';)

c) et ajoutez des sockets à la ligne 37 de app.js (ie 'socket.sockets.on (' connection ', function (client) {…')

dirkk0
la source
0

selon la solution @alex . si vous avez une erreur comme celle-ci selon la mention @tyler :

node.js:134
        throw e; // process.nextTick error, or 'error'

event on first tick ^ Error: Redis connection to 127.0.0.1:6379 failed - ECONNREFUSED, Connection refused at Socket.

vous devez d'abord installer Redis . regarde ça:

http://redis.io/download

hbinduni
la source