Проведя некоторое исследование, я решил использовать нодальный модуль событий Node для решения этой проблемы.В этом примере вместо * node_redis используется ioredis , но принцип тот же.
Сначала я создаю три клиента Redis.Один для обычной работы с БД, издатель и подписчик
/* redis.js */
const Redis = require('ioredis');
const redis = new Redis();
const publisher = new Redis();
const subscriber = new Redis();
// redis is the defaut export
// publisher and subscriber are "named" exports
const client = (module.exports = redis);
client.publisher = publisher;
client.subscriber = subscriber;
Затем мы создаем узел EventEmitter
, который будет генерировать событие каждый раз, когда подписчик получает сообщение от канала в redis.
/* emitter.js */
const EventEmitter = require('events');
const { subscriber } = require('./redis');
const eventEmitter = new EventEmitter();
subscriber.subscribe('my-channel', err => {
if (err) { return console.log('Unable to subscribe to my-event channel') };
console.log('Subscription to my-event channel successful');
});
subscriber.on('message', (channel, message) => {
eventEmitter.emit('my-event', message);
});
module.exports = eventEmitter;
Здесь у нас есть два маршрута.Первый обрабатывает запрос PUT, который устанавливает поле в redis, а затем публикует сообщение на канал с ключом хэша, который был обновлен.Второй маршрут обрабатывает GET-запрос, который остается открытым (например, в качестве EventSource для соединения SSE).Он прослушивает событие от эмиттера, а затем отправляет данные обновленного ключа из redis
/* route.js*/
const express = require('express');
const redis = require('./redis');
const { publisher } = require('./redis');
const { eventEmitter } = require('./emitter');
const router = express.Router();
router.put('/content', async (req, res) => {
const { key, field, content } = req.body;
try {
await redis.hset(key, field, content);
res.sendStatus(200);
return publisher.publish('my-channel', key);
} catch(err) {
res.status(500).send(err.message);
}
});
router.get('/content-stream', (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive'
});
res.write('\n');
const handleEvent = async key => {
try {
const query = await redis.hgetall(key);
res.write(`data: ${JSON.stringify(query)}\n\n`);
} catch(err) {
console.log('Something went wrong');
}
}
eventEmitter.addListener('my-event', handleEvent);
req.on('close', eventEmitter.removeListener('my-event', handleEvent));
module.exports = router;
Это эффективно позволит вам избежать создания новых клиентов redis при каждом подключении.Возможно, есть лучшие способы сделать это, но это то, что сработало для меня.