ルモーリン

RedisのPubSubを使ってプロセス間通信

投稿:2021-03-08

プリフォーク型のWebサーバに移行したらワーカープロセスが複数稼働するので処理を同期させたい。

サーバー側です。
Redis
Mojoliciousが使うクライアントはこちら。
Mojo::Redis - Redis driver based on Mojo::IOLoop - metacpan.org

ワーカープロセス(アプリケーション)に1個だけRedisオブジェクトを作り、使う所は全部このオブジェクトを利用することにしました。 そこで起動時にオブジェクトとそれを返すヘルパー関数を登録します。 オブジェクトの種類や保管場所を変更する際にヘルパー関数の修正で済むようにします。 おまけでRedisを使う瞬間にヘルパー関数が呼ばれるのでデバッグの補助になれば良いなと考えています。

package AppRedis;
use Mojo::Base "Mojolicious::Plugin";

use Mojo::Redis;

sub register {
        my ($self, $app, $conf) = @_;

        $app->{redis} = Mojo::Redis->new;

        $app->helper(AppRedis => sub {
                my $self = shift;

                return $self->app->{redis};
        });
}

1;

他のプロセスへ連絡する場合はnotifyを呼びます。
Mojo::Redis::PubSub - Publish and subscribe to Redis messages - metacpan.org
AppRedisはヘルパー関数なのでMojo::Redisオブジェクトを返し、そのpubsubからnotifyメソッドを呼びます。 引数1個目はpubsubのチャンネル名、2個目はメッセージです。 チャンネル名は将来の増加に備えて「アプリケーション:機能:種別」を文字列にしています。

$self->AppRedis->pubsub->notify("mojolicious:update:messages", "load");

メッセージを受け取る場合は予めlistenを呼びます。 チャンネル名を指定してコールバックを登録します。 Publish同様、AppRedisからオブジェクトを受け取りpubsubのlistenメソッドを呼びます。 チャンネル名がPublishと一致する所に注目してください。 コールバックの中で届いたメッセージをチェックして予定通りであれば処理を継続します。 この例にあるPpUpdateLoadは更新情報をロードする処理ですがPubSubとは特に関係ありません。 一見するとnotifyからコールバックするように見えますが、notifyからRedisサーバーに届き、そこからlistenで登録しているクライアント全てに届き、全てのワーカープロセスのコールバックが呼ばれます。

$app->AppRedis->pubsub->listen("mojolicious:update:messages" => sub {
	my ($pubsub, $message) = @_;

	if ("load" eq $message) {
		$app->PpUpdateLoad;
	}
});