Server発でclientにメッセージを送りたくなった
元々nodeで作ったwebsocket serverでclient側と双方向通信をしていたんですが、別サーバやbatch処理などでの更新処理をトリガーとしてclient(の従来で使用しているchannel)にメッセージを送りたくなりました。
そこでいろいろ探してたら、redisにpub/sub機能というのがあり、それを使えば上手くいきそうなのでやってみました。
実装のイメージ
# 使ったモジュール * [redis pub/sub](https://redis.io/topics/pubsub) * 他のサーバでの変更を検知するために使用 * [socket.io-emitter](https://github.com/socketio/socket.io-emitter) * サーバ側からclientにメッセージを送るためのモジュール * [socket.io-redis](https://github.com/socketio/socket.io-redis) * 異なるプロセスやサーバ間で動いているwebsocketサービスで接続先情報をredisで共有し、正常にemitやbroadcastを行えるようにするためのモジュールインストール
$ npm i -S redis
$ npm i -S socket.io
$ npm i -S socket.io-emitter
$ npm i -S socket.io-redis
#実装
まず、従来のsocketサービスの接続先を共有するために、socket.io-redisを入れる。
// socket-server
const io = require('socket.io')(); // for socket server
const socketRedis = require('socket.io-redis');
// 接続先情報をredisに保存
io.adapter(socketRedis({
host: 'localhost', //サンプルなので一旦ローカルのredisを参照
port: 6379,
}));
// 〜〜〜従来のsocket処理〜〜〜
次に、サーバ発のメッセージを送るためにio-emitterを入れる。
// 先ほどと同じredis情報を渡して起動することで、接続情報を共有
const emitter = ioEmitter({
host: 'localhost',
port: 6379,
});
最後にredisのsubscriberを作成し、それをトリガーとしてio emitterでclientにemitする。
const redis = require('redis');
// subscribeする用のredis clientを作成
// ここではめんどくさかったので、接続情報を登録するものと同じものを使用
const Subscriber = redis.createClient(6379, 'localhost');
// redis-publisherからのメッセージを受け取るチャンネルを登録
Subscriber.subscribe('SUBSCRIBE_CHANNEL');
exports.register = (emitter) => {
Subscriber.on('message', (channel, message) => {
switch (channel) {
// 該当のチャンネルにメッセージが飛ばされたら場合分けして処理
case 'SUBSCRIBE_CHANNEL':
emitter.to('CLIENT_CHANNEL').emit('Hello!! I am redis-subscriber.');
break;
}
});
};
これで、別サーバにからredisのpublisherを使って「SUBSCRIBE_CHANNEL」にメッセージを送れば、フロントで「CLIENT_CHANNEL」を開いている全員に向けて「Hello!! I am redis-subscriber.」というメッセージを通知できる。
最後に
redisのpub/subとsocket.io-emitterを使ったら、他のサーバと同期を取りながらいい感じにフロントに通知を送ることができるようになりました。
サンプルはここに置いておきましたのでよろしければご参照ください。
間違い等あったら教えてくれると嬉しいです。