Come utilizzare redis PUBLISH / SUBSCRIBE con nodejs per notificare ai clienti quando i valori dei dati cambiano?


99

Sto scrivendo un'applicazione di pubblicazione / sottoscrizione basata su eventi con NodeJS e Redis. Ho bisogno di un esempio di come notificare ai client Web quando i valori dei dati in Redis cambiano.

Risposte:


123

OLD usa solo un riferimento

Dipendenze

utilizza express , socket.io , node_redis e, ultimo ma non meno importante, il codice di esempio di media fire.

Installa node.js + npm (come non root)

Per prima cosa dovresti (se non l'hai ancora fatto) installare node.js + npm in 30 secondi (nel modo giusto perché NON dovresti eseguire npm come 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

Installa le dipendenze

Dopo aver installato node + npm dovresti installare le dipendenze emettendo:

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

Scarica campione

È possibile scaricare un campione completo da mediafire .

Decomprimere il pacchetto

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

Cosa c'è dentro la 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>

Avvia il server

cd pbsb    
node app.js

Avvia il browser

Meglio se avvii Google Chrome (a causa del supporto websocket, ma non necessario). Visita http://localhost:3000per vedere un campione (all'inizio non vedi altro che PubSubcome titolo).

Ma sul publishcanale pubsubdovresti vedere un messaggio. Di seguito pubblichiamo "Hello world!"sul browser.

Da ./redis-cli

publish pubsub "Hello world!"

perché hai bisogno const client = redis.createClient()nella root di app.js?
Akasha

non è necessario utilizzare affatto const. var potrebbe essere usato anche e forse dovrei averlo invece perché const è disponibile solo nei motori javascript più recenti. Inoltre questa linea garantisce che siamo connessi al server redis che usiamo in questo esempio.
Alfred

5
L'esempio è molto vecchio, quindi non aggiornato con gli ultimi moduli socket.io/express e forse anche con node.js. Proverei ad aggiornare il codice. C'è anche un altro enorme problema con questo codice che apre un'altra connessione Redis per ogni utente connesso. Dovrebbe essere acceso solo invece. Prima devo lavorare, ma dopo provo ad aggiornare il codice.
Alfred

1
Molto bene. Penso ancora che ci sia spazio per alcuni miglioramenti che quando avrò tempo metterò online. Ma in questo momento sto davvero lavorando sodo: $.
Alfred

1
Penso che subscribe.on dovrebbe essere al di fuori del blocco socket.on ('connection') per evitare sottoscrizioni multiple /
zubinmehta

26

ecco un esempio semplificato senza tante dipendenze. Ne hai ancora bisognonpm install hiredis redis

Il nodo JavaScript:

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

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

... mettilo in un file pubsub.js ed esegui node pubsub.js

in redis-cli:

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

che dovrebbe visualizzare: pubsub: Hello Wonky!nel terminale che esegue il nodo! Congratulazioni!

23/4/2013 aggiuntivo: Voglio anche sottolineare che quando un client si iscrive a un canale pub / sub, entra in modalità abbonato ed è limitato ai comandi dell'abbonato. Dovrai solo creare istanze aggiuntive di client redis. client1 = redis.createClient(), client2 = redis.createClient()quindi uno può essere in modalità sottoscrittore e l'altro può emettere comandi DB regolari.


Qui quando aggiungiamo dati al redis, devo eseguire publish pubsub per ricevere la notifica dell'inserimento?
IshaS

1
@IshaS, se è quello che devi fare, sì. Dovresti anche esaminare le transazioni se devi eseguire più comandi in modo atomico: redis.io/commands/exec
nak

@nak Questo ha funzionato alla perfezione in un unico GO :) Alcuni utenti potrebbero aver bisogno di installare 'double-ended-queue' se non è già installato.
Alex

1
Vale anche la pena ricordare che se si desidera utilizzare i caratteri jolly, ad esempio, iscriversi per pubsub/*aggiungere semplicemente pall'esempio: sostituire subscibecon psubscribee messagecon pmessage.
Liosha Bakoushin,

7

Esempio completo di Redis Pub / Sub ( chat in tempo reale con Hapi.js e Socket.io)

Stavamo cercando di capire Redis Publish / Subscribe (" Pub / Sub ") e tutti gli esempi esistenti erano obsoleti, troppo semplici o non presentavano test. Quindi abbiamo scritto una chat completa in tempo reale usando Hapi.js + Socket.io + Redis Pub / Sub Example con test end-to-end !

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

Il componente Pub / Sub è solo poche righe di codice node.js: https://github.com/dwyl/hapi-socketio-redis-chat-example/blob/master/lib/chat.js#L33-L40

Invece di incollarlo qui ( senza alcun contesto ) ti invitiamo a fare il checkout / provare l' esempio .

L'abbiamo creato utilizzando Hapi.js ma il chat.jsfile è disaccoppiato da Hapi e può essere facilmente utilizzato con un server HTTP node.js di base o express (ecc.)


hai questo esempio con express?
Gixty

@Gixty abbiamo scritto l'esempio usando Hapi.js perché tutti gli altri esempi là fuori usano Express.js ... come menzionato nel post, è banale portarlo su qualsiasi altro framework Node.js (passa semplicemente nell'app express / listener al codice di inizializzazione chat.js) e funziona esattamente allo stesso modo. ps: se sei nuovo su Hapi.js vedi: github.com/nelsonic/learn-hapi
nelsonic

4

Gestisci gli errori redis per impedire la chiusura di nodejs. Puoi farlo scrivendo;

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

Penso che tu ottenga l'eccezione perché stai usando lo stesso client a cui è iscritto per pubblicare i messaggi. Crea un client separato per la pubblicazione dei messaggi e questo potrebbe risolvere il tuo problema.



2

Se vuoi farlo funzionare con socket.io 0.7 E un server web esterno devi cambiare (oltre a staticProvider -> problema statico):

a) fornire il nome del dominio invece di localhost (ad esempio var socket = io.connect ('http://my.domain.com:3000');) nel file index.html

b) cambia HOST in app.js (es. const HOST = 'my.domain.com';)

c) e aggiungi i socket nella riga 37 di app.js (cioè 'socket.sockets.on (' connection ', function (client) {…')



0

secondo la soluzione @alex . se hai un errore come questo come da menzione @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.

quindi devi prima installare Redis . controllalo:

http://redis.io/download

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.