Wie verwende ich redis PUBLISH / SUBSCRIBE mit nodejs, um Clients zu benachrichtigen, wenn sich Datenwerte ändern?

99

Ich schreibe eine ereignisgesteuerte Publish / Subscribe-Anwendung mit NodeJS und Redis. Ich benötige ein Beispiel, wie Webclients benachrichtigt werden, wenn sich die Datenwerte in Redis ändern.

guilin 桂林
quelle

Antworten:

123

ALT nur eine Referenz verwenden

Abhängigkeiten

verwendet express , socket.io , node_redis und nicht zuletzt den Beispielcode von media fire.

Installieren Sie node.js + npm (als nicht root)

Zuerst sollten Sie (falls Sie dies noch nicht getan haben) node.js + npm in 30 Sekunden installieren (der richtige Weg, da Sie npm NICHT als root ausführen sollten ):

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

Abhängigkeiten installieren

Nachdem Sie node + npm installiert haben, sollten Sie Abhängigkeiten installieren, indem Sie Folgendes ausgeben:

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

Beispiel herunterladen

Sie können das vollständige Beispiel von mediafire herunterladen .

Paket entpacken

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

Was ist in Reißverschluss

./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>

Server starten

cd pbsb    
node app.js

Starten Sie den Browser

Am besten, wenn Sie Google Chrome starten (wegen der Unterstützung von Websockets, aber nicht erforderlich). Besuchen Sie http://localhost:3000, um das Beispiel zu sehen (am Anfang sehen Sie nichts anderes PubSubals den Titel).

Aber auf publishKanal pubsubsollten Sie eine Nachricht sehen. Unten veröffentlichen wir "Hello world!"im Browser.

Von ./redis-cli

publish pubsub "Hello world!"
Alfred
quelle
Warum brauchst du const client = redis.createClient()im Stammverzeichnis von app.js?
Akasha
Sie müssen const überhaupt nicht verwenden. var könnte auch verwendet werden und sollte ich vielleicht stattdessen haben, weil const nur in den neueren Javascript-Engines verfügbar ist. Darüber hinaus stellt diese Leitung sicher, dass wir mit dem Redis-Server verbunden sind, den wir in diesem Beispiel verwenden.
Alfred
5
Das Beispiel ist sehr alt, daher nicht auf dem neuesten Stand der neuesten socket.io/express-Module und möglicherweise sogar node.js. Ich würde versuchen, den Code zu aktualisieren. Es gibt auch ein weiteres großes Problem mit diesem Code, dass für jeden verbundenen Benutzer eine weitere Redis-Verbindung geöffnet wird. Das sollte stattdessen nur eingeschaltet sein. Ich muss zuerst arbeiten, aber danach versuche ich, den Code zu aktualisieren.
Alfred
1
Sehr gut. Ich denke immer noch, dass es Raum für einige Verbesserungen gibt, die ich, wenn ich Zeit habe, online stellen werde. Aber im Moment arbeite ich wirklich hart: $.
Alfred
1
Ich denke, subscribe.on sollte sich außerhalb des Blocks socket.on ('connection') befinden, um Mehrfachabonnements zu vermeiden /
zubinmehta
26

Hier ist ein vereinfachtes Beispiel ohne so viele Abhängigkeiten. Sie müssen nochnpm install hiredis redis

Der Knoten JavaScript:

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

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

... das in eine pubsub.js Datei legen und ausführen node pubsub.js

in redis-cli:

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

was angezeigt werden sollte: pubsub: Hello Wonky!im Terminal läuft Knoten! Glückwunsch!

Zusätzliches 23.04.2013: Ich möchte auch darauf hinweisen, dass ein Client, der einen Pub / Sub-Kanal abonniert, in den Abonnentenmodus wechselt und auf Abonnentenbefehle beschränkt ist. Sie müssen nur zusätzliche Instanzen von Redis-Clients erstellen. client1 = redis.createClient(), client2 = redis.createClient()So kann sich einer im Abonnentenmodus befinden und der andere kann reguläre DB-Befehle ausgeben.

nak
quelle
Sollte ich hier, wenn wir Daten zu den Redis hinzufügen, Publish Pubsub ausführen, um eine Benachrichtigung über das Einfügen zu erhalten?
IshaS
1
@IshaS wenn du das tun musst, ja. Sie sollten sich auch Transaktionen ansehen, wenn Sie mehrere Befehle atomar ausführen müssen: redis.io/commands/exec
nak
@nak Dies funktionierte wie ein Zauber in einem GO :) Einige Benutzer müssen möglicherweise 'Double-Ended-Queue' installieren, wenn dies nicht bereits installiert ist.
Alex
1
Es ist auch erwähnenswert, dass Sie, wenn Sie beispielsweise Platzhalter verwenden möchten, abonnieren, um pubsub/*nur pdas Beispiel zu ergänzen : Ersetzen subscibedurch psubscribeund messagedurch pmessage.
Liosha Bakoushin
7

Vollständiges Redis Pub / Sub-Beispiel ( Echtzeit-Chat mit Hapi.js & Socket.io)

Wir haben versucht, Redis Publish / Subscribe (" Pub / Sub ") zu verstehen, und alle vorhandenen Beispiele waren entweder veraltet, zu einfach oder hatten keine Tests. Also haben wir einen vollständigen Echtzeit-Chat mit Hapi.js + Socket.io + Redis Pub / Sub-Beispiel mit End-to-End-Tests geschrieben !

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

Die Pub / Sub-Komponente besteht nur aus wenigen Zeilen des node.js-Codes: https://github.com/dwyl/hapi-socketio-redis-chat-example/blob/master/lib/chat.js#L33-L40

Anstatt es hier ( ohne Kontext ) einzufügen , empfehlen wir Ihnen, das Beispiel zu überprüfen / auszuprobieren .

Wir bauten es mit Hapi.js aber die chat.jsDatei ist entkoppelten von Hapi und kann leicht mit einem verwendet werden grundlegende node.js HTTP - Server oder Express (etc.)

nelsonic
quelle
Haben Sie dieses Beispiel mit Express?
Gixty
@Gixty Wir haben das Beispiel mit Hapi.js geschrieben, da alle anderen Beispiele Express.js verwenden ... wie im Beitrag erwähnt, ist es trivial, es auf ein anderes Node.js-Framework zu portieren (einfach in der Express-App übergeben / Listener auf den Init-Code von chat.js) und es funktioniert genauso. ps: Wenn Sie neu bei Hapi.js sind, sehen Sie: github.com/nelsonic/learn-hapi
nelsonic
4

Behandeln Sie Redis-Fehler, um das Beenden von NodeJS zu verhindern. Sie können dies durch Schreiben tun;

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

Ich denke, Sie erhalten die Ausnahme, weil Sie denselben Client verwenden, der zum Veröffentlichen von Nachrichten abonniert ist. Erstellen Sie einen separaten Client zum Veröffentlichen von Nachrichten, um Ihr Problem zu lösen.

Awemo
quelle
2

Wenn Sie dies mit socket.io 0.7 UND einem externen Webserver zum Laufen bringen möchten, müssen Sie dies ändern (neben dem staticProvider -> static-Problem):

a) Geben Sie den Domainnamen anstelle von localhost (dh var socket = io.connect ('http://my.domain.com:3000');) in der index.html an

b) Ändern Sie HOST in app.js (dh const HOST = 'my.domain.com';)

c) und fügen Sie Sockets in Zeile 37 von app.js hinzu (dh 'socket.sockets.on (' Verbindung ', Funktion (Client) {…')

dirkk0
quelle
0

gemäß @alex Lösung. Wenn Sie einen Fehler wie diesen gemäß @tyler haben, erwähnen Sie:

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.

Dann müssen Sie zuerst Redis installieren . Schau dir das an:

http://redis.io/download

hbinduni
quelle