Как использовать redis PUBLISH / SUBSCRIBE с nodejs для уведомления клиентов об изменении значений данных?


99

Я пишу управляемое событиями приложение публикации / подписки с помощью NodeJS и Redis. Мне нужен пример того, как уведомлять веб-клиентов при изменении значений данных в Redis.

Ответы:


123

СТАРЫЙ используйте только ссылку

Зависимости

использует express , socket.io , node_redis и, наконец, что не менее важно , пример кода из media fire.

Установите node.js + npm (как не root)

Сначала вы должны (если вы еще этого не сделали) установить node.js + npm за 30 секунд (правильный способ, потому что вы НЕ должны запускать npm как 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

Установить зависимости

После того, как вы установили node + npm, вы должны установить зависимости, выполнив:

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

Скачать образец

Вы можете скачать полный образец с сайта mediafire .

Распаковать пакет

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

Что внутри 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>

Запустить сервер

cd pbsb    
node app.js

Запустить браузер

Лучше всего, если вы запустите google chrome (из-за поддержки веб-сокетов, но не обязательно). Посетите, http://localhost:3000чтобы увидеть образец (в начале вы не видите ничего, кроме PubSubназвания).

Но на publishканале pubsubвы должны увидеть сообщение. Ниже публикуем "Hello world!"в браузере.

От ./redis-cli

publish pubsub "Hello world!"

зачем вам const client = redis.createClient()в корне app.js?
Akasha

вам вообще не нужно использовать const. var тоже можно было бы использовать, и, возможно, мне следовало бы его использовать, потому что const доступна только в новых движках javascript. Кроме того, эта строка гарантирует, что мы подключены к серверу redis, который мы используем в этом примере.
Альфред

5
Образец очень старый, поэтому он не обновлен с последними модулями socket.io/express и, возможно, даже с node.js. Я бы попробовал обновить код. Есть еще одна серьезная проблема с этим кодом, заключающаяся в том, что он открывает еще одно соединение Redis для каждого подключенного пользователя. Это должно быть только вместо этого. Мне сначала нужно поработать, а потом я пытаюсь обновить код.
Альфред,

1
Очень хорошо. Я все еще думаю, что есть возможности для некоторых улучшений, которые, когда у меня будет время, я выложу онлайн. Но сейчас я очень много работаю: $.
Alfred

1
Я думаю, что subscribe.on должен находиться за пределами блока socket.on ('connection'), чтобы избежать множественных
подписок

26

вот упрощенный пример без стольких зависимостей. Вам все еще нужноnpm install hiredis redis

Узел JavaScript:

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

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

... поместите это в файл pubsub.js и запустите node pubsub.js

в redis-cli:

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

который должен отображать: pubsub: Hello Wonky!в терминальном рабочем узле! Поздравляю!

Дополнительно 23.04.2013: Я также хочу отметить, что когда клиент подписывается на pub / sub канал, он переходит в режим подписчика и ограничивается командами подписчика. Вам просто нужно создать дополнительные экземпляры клиентов Redis. client1 = redis.createClient(), client2 = redis.createClient()так что один может быть в режиме подписчика, а другой может выдавать обычные команды БД.


Здесь, когда мы добавляем данные в Redis, должен ли я запускать Pubsubsub, чтобы получить уведомление о вставке?
IshaS 07

1
@IshaS, если это то, что вам нужно, да. Вы также должны смотреть на сделки , если вам нужно выполнить несколько команд атомарно: redis.io/commands/exec
NAK

@nak Это сработало как шарм в одном GO :) Некоторым пользователям может потребоваться установить «двустороннюю очередь», если она еще не установлена.
Manjeet

1
Также стоит упомянуть, что если вы хотите использовать подстановочные знаки, например, подпишитесь, чтобы pubsub/*просто добавить pв пример: заменить subscibeна psubscribeи messageна pmessage.
Леша Бакушин,

7

Полный пример Redis Pub / Sub ( чат в реальном времени с использованием Hapi.js и Socket.io)

Мы пытались понять Redis Publish / Subscribe (« Pub / Sub »), и все существующие примеры были либо устаревшими, либо слишком простыми, либо не имели тестов. Итак, мы написали полный чат в реальном времени, используя Hapi.js + Socket.io + Redis Pub / Sub Example со сквозными тестами !

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

Компонент Pub / Sub - это всего несколько строк кода node.js: https://github.com/dwyl/hapi-socketio-redis-chat-example/blob/master/lib/chat.js#L33-L40

Вместо того, чтобы вставлять его сюда ( без какого-либо контекста ), мы рекомендуем вам проверить / попробовать этот пример .

Мы построили его с помощью Hapi.js , но chat.jsфайл отсоединено от Хапи и может легко использоваться с базовым node.js HTTP - сервером или выразить ( и т.д.)


у вас есть этот пример с экспрессом?
Gixty

@Gixty, мы написали пример, используя Hapi.js, потому что все другие примеры используют Express.js ... как упоминалось в сообщении, его тривиально перенести на любую другую структуру Node.js (просто передайте в экспресс-приложение / слушатель кода инициализации chat.js), и он работает точно так же. ps: если вы новичок в Hapi.js, см .: github.com/nelsonic/learn-hapi
nelsonic

4

Обрабатывайте ошибки redis, чтобы остановить выход nodejs. Вы можете сделать это, написав;

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

Я думаю, что вы получаете исключение, потому что вы используете тот же клиент, который подписан на публикацию сообщений. Создайте отдельный клиент для публикации сообщений, и это может решить вашу проблему.



2

Если вы хотите, чтобы это работало с socket.io 0.7 И внешним веб- сервером, вам нужно изменить (помимо staticProvider -> static):

a) укажите имя домена вместо localhost (например, var socket = io.connect ('http://my.domain.com:3000');) в index.html

б) изменить HOST в app.js (т.е. const HOST = 'my.domain.com';)

c) и добавьте сокеты в строку 37 файла app.js (например, 'socket.sockets.on (' соединение ', функция (клиент) {…')



0

согласно решению @alex . если у вас есть такая ошибка, как указано в @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.

тогда вам нужно сначала установить Redis . Проверь это:

http://redis.io/download

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.