Jak używać redis PUBLISH / SUBSCRIBE z nodejs do powiadamiania klientów o zmianie wartości danych?

99

Piszę opartą na zdarzeniach aplikację publikowania / subskrybowania z NodeJS i Redis. Potrzebuję przykładu, jak powiadamiać klientów WWW o zmianie wartości danych w Redis.

guilin 桂林
źródło

Odpowiedzi:

123

OLD używaj tylko odniesienia

Zależności

używa express , socket.io , node_redis i wreszcie przykładowy kod z media fire.

Zainstaluj node.js + npm (jako użytkownik inny niż root)

Najpierw powinieneś (jeśli jeszcze tego nie zrobiłeś) zainstalować node.js + npm w 30 sekund (właściwy sposób, ponieważ NIE powinieneś uruchamiać npm jako 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

Zainstaluj zależności

Po zainstalowaniu node + npm powinieneś zainstalować zależności, wydając:

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

Pobierz próbkę

Możesz pobrać pełną próbkę z mediafire .

Rozpakuj pakiet

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

Co znajduje się wewnątrz zamka błyskawicznego

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

Uruchom serwer

cd pbsb    
node app.js

Uruchom przeglądarkę

Najlepiej, jeśli uruchomisz Google Chrome (ze względu na obsługę gniazd sieciowych, ale nie jest to konieczne). Odwiedź, http://localhost:3000aby zobaczyć próbkę (na początku nie widzisz niczego, ale PubSubjako tytuł).

Ale na publishkanale pubsubpowinieneś zobaczyć wiadomość. Poniżej publikujemy "Hello world!"w przeglądarce.

Od ./redis-cli

publish pubsub "Hello world!"
Alfred
źródło
dlaczego potrzebujesz const client = redis.createClient()w katalogu głównym app.js?
Akasha
nie musisz w ogóle używać const. var mógłby być również użyty i być może powinienem był zamiast tego, ponieważ const jest dostępne tylko w nowszych silnikach javascript. Ponadto ta linia zapewnia, że ​​jesteśmy połączeni z serwerem redis, którego używamy w tym przykładzie.
Alfred,
5
Próbka jest bardzo stara, więc nie jest aktualna z najnowszymi modułami socket.io/express, a może nawet node.js. Spróbowałbym zaktualizować kod. Jest też inny ogromny problem z tym kodem, który otwiera kolejne połączenie redis dla każdego podłączonego użytkownika. Zamiast tego powinno być włączone. Najpierw muszę pracować, ale później próbuję zaktualizować kod.
Alfred
1
Bardzo dobrze. Nadal uważam, że jest miejsce na pewne ulepszenia, które gdy będę miał czas, umieszczę je online. Ale teraz naprawdę ciężko pracuję: $.
Alfred,
1
Myślę, że subscribe.on powinno znajdować się poza blokiem socket.on ('connection'), aby uniknąć wielu subskrypcji /
zubinmehta
26

oto uproszczony przykład bez tylu zależności. Nadal musisznpm install hiredis redis

Węzeł JavaScript:

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

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

... umieść to w pliku pubsub.js i uruchom node pubsub.js

w redis-cli:

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

który powinien wyświetlić: pubsub: Hello Wonky!w węźle działającym terminala! Gratulacje!

Dodatkowe 23.04.2013: Chcę również zauważyć, że kiedy klient subskrybuje kanał pub / sub, przechodzi w tryb subskrybenta i jest ograniczony do poleceń subskrybenta. Musisz tylko utworzyć dodatkowe wystąpienia klientów redis. client1 = redis.createClient(), client2 = redis.createClient()więc jeden może być w trybie abonenta, a drugi może wydawać regularne polecenia DB.

nak
źródło
Tutaj, kiedy dodamy dane do redis, czy powinienem uruchomić publikację pubsub, aby otrzymać powiadomienie o wstawieniu?
IshaS,
1
@IshaS, jeśli to jest to, co musisz zrobić, tak. Powinieneś również przyjrzeć się transakcjom, jeśli chcesz uruchomić wiele poleceń niepodzielnie: redis.io/commands/exec
nak
@nak To działało jak urok w jednym GO :) Niektórzy użytkownicy mogą potrzebować zainstalować „podwójną kolejkę”, jeśli nie została jeszcze zainstalowana.
Manjeet
1
Warto również wspomnieć, że jeśli chcesz używać symboli wieloznacznych, na przykład, zapisz się pubsub/*po prostu dodać pdo przykładu: wymienić subscibez psubscribei messagez pmessage.
Liosha Bakoushin
7

Kompletny przykład Redis Pub / Sub ( czat w czasie rzeczywistym przy użyciu Hapi.js i Socket.io)

Próbowaliśmy zrozumieć Redis Publish / Subscribe („ Pub / Sub ”) i wszystkie istniejące przykłady były albo nieaktualne, zbyt proste lub nie miały testów. Dlatego napisaliśmy kompletny czat w czasie rzeczywistym przy użyciu Hapi.js + Socket.io + Redis Pub / Sub Przykład z testami od końca do końca !

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

Komponent Pub / Sub to tylko kilka wierszy kodu node.js: https://github.com/dwyl/hapi-socketio-redis-chat-example/blob/master/lib/chat.js#L33-L40

Zamiast wklejać go tutaj ( bez żadnego kontekstu ), zachęcamy do zakupu / wypróbowania przykładu .

Zbudowaliśmy go za pomocą Hapi.js ale chat.jsplik jest de-sprzężony z Hapi i może łatwo być używane z podstawowego node.js serwer HTTP lub wyrażenia (itd.)

nelsonic
źródło
czy masz ten przykład z ekspresem?
Gixty
@Gixty napisaliśmy przykład przy użyciu Hapi.js, ponieważ wszystkie inne przykłady używają Express.js ... jak wspomniano w poście, jest to trywialne, aby przenieść go do dowolnego innego frameworka Node.js (po prostu przekaż aplikację ekspresową / słuchacza kodu inicjującego chat.js) i działa dokładnie tak samo. ps: jeśli jesteś nowy w Hapi.js, zobacz: github.com/nelsonic/learn-hapi
nelsonic
4

Obsługuj błędy redis, aby zatrzymać wyjście nodejs. Możesz to zrobić pisząc;

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

Myślę, że otrzymujesz wyjątek, ponieważ używasz tego samego klienta, który subskrybuje publikowanie wiadomości. Utwórz oddzielnego klienta do publikowania wiadomości, który może rozwiązać Twój problem.

Awemo
źródło
2

Jeśli chcesz, aby to działało z socket.io 0.7 ORAZ zewnętrznym serwerem internetowym, musisz zmienić (oprócz staticProvider -> problem statyczny):

a) podać nazwę domeny zamiast localhost (np. var socket = io.connect ('http://my.domain.com:3000');) w pliku index.html

b) zmień HOST w app.js (tj. const HOST = 'my.domain.com';)

c) i dodaj gniazda w linii 37 pliku app.js (tj. „socket.sockets.on ('connection', function (client) {… '')

dirkk0
źródło
0

zgodnie z rozwiązaniem @alex . jeśli masz taki błąd, jak na wzmiankę @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.

następnie musisz najpierw zainstalować Redis . Sprawdź to:

http://redis.io/download

hbinduni
źródło