RedisのPub/Sub機能を使って、Laravel の管理画面から、NuxtJSにリアルタイム配信を行ったときのメモを残す。
実行環境
- Laravel 6.20.26
- Laravel Echo Server
https://hub.docker.com/r/oanhnn/laravel-echo-server - Redis 6.2.4
- phpredis
https://github.com/phpredis/phpredis/blob/develop/INSTALL.markdown - nuxtJS 2.15.3
- socket.io-client 2.3.0
- @nuxtjs/laravel-echo 1.1.0
Laravelでブロードキャストする仕様整理
Laravelの公式ドキュメントを確認すると、以下のような記載があり、自分の理解を追記。
多くの近代的なアプリケーションでは、リアルタイムでライブ更新されるユーザーインターフェイスを実装するために、WebSocketが使用されています。
WebSocketとは、WebサーバとWebブラウザの間で双方向通信できるようにする通信プロトコル。
サーバ側から任意のタイミングで送信を開始でき、プッシュ型の情報配信アプリケーションの構築ができる技術仕様。
Webページを表示している間、定期的に通信を行い、メッセージの受信確認を行ってくれる機能。
Laravelはドライバをいくつか準備しています。PusherチャンネルやRedis、それにローカルの開発とデバッグのためのlogドライバがあります。
今回は、Redisを使って進める。
Pusherは外部サービスだし、logドライバは実運用できないので、一択。
Redisブロードキャスタを使用する場合は、phpredis PHP拡張をPECLを使いインストールするか、PredisライブラリをComposerを使用しインストールする必要があります。
今回は、phpredisを使って進める。Predisはメンテナンス終了しているとのことなので。
RedisブロードキャスタはRedisのpub/sub機能を使用し、メッセージをブロードキャストします。Redisからのメッセージを受け、WebSocketチャンネルへブロードキャストできるように、これをWebSocketとペアリングする必要があります。
Redisのpub/sub機能とは、「チャンネルA」に対して、Publisher(発信者)とSubscriber(購読者)を準備すると、Publisherがメッセージを送信したら、即座にSubscriber宛にメッセージが届くというもの。
Subscriber(購読者)が大量にいても、即座に届く。
RedisのPub/Sub機能とWebSocketを連携することで、ブラウザ上にメッセージを表示できるようになるということ。
RedisブロードキャスタとSocket.IOサーバをペアリングする場合、アプリケーションへSocket.IO JavaScriptクライアントライブラリをインクルードする必要があります。
npm install –save socket.io-client
NuxtJSでソケット通信を行うので、nuxtコミュニティのlaravel-echoライブラリとSocket.IO-Clientをインストールする。
Socket.IOのコンパチブルサーバを実行する必要があります。LaravelにはSocket.IOサーバの実装は含まれていません。しかし、tlaverdure/laravel-echo-server GitHubリポジトリで、コミュニティにより現在、Socket.IOサーバがメンテナンスされています。
Laravel Echo ServerのDockerコンテナを立ち上げる
環境構築(送信側設定)
php実行環境にredisとecho-serverをセットアップし、public-eventチャンネルに対して、メッセージを配信する設定を行う。
docker-compose.yml
php実行環境にredisコンテナとecho-serverコンテナを追加する
version: '3.6'
services:
redis:
image: "redis:latest"
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
app_net:
ipv4_address: 172.21.0.14
echo-server:
image: broadcast-echo-server
depends_on:
- redis
build: ./docker/echoserver
ports:
- "6001:6001"
command: laravel-echo-server start
volumes:
- ./danroo-api:/work:cached
working_dir: /work
networks:
app_net:
ipv4_address: 172.21.0.15
volumes:
redis-data:
phpコンテナ用Dockerfile
phpコンテナ用のDockerfileで、phpredisライブラリをインストールする
RUN pecl install redis \
&& docker-php-ext-enable redis
laravel-echo-server.json
コマンドから「laravel-echo-server init」を実行して、laravel-echo-server.json を作成する
$ docker-compose run --rm echo-server laravel-echo-server init
? Do you want to run this server in development mode? Yes
? Which port would you like to serve from? 6001
? Which database would you like to use to store presence channel members? redis
? Enter the host of your Laravel authentication server.
? Will you be serving on http or https? http
? Do you want to generate a client ID/Key for HTTP API? Yes
? Do you want to setup cross domain access to the API? No
? What do you want this config to be saved as? laravel-echo-server.json
appId: 123abc...
key: abc123....
Configuration file saved. Run laravel-echo-server start to run server.
Redisの接続設定を追記する
"database": "redis",
"databaseConfig": {
"redis": {
"host": "redis",
"port": 6379
}
},
.env
以下を追加(抜粋)
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379
REDIS_CLIENT=phpredis
REDIS_PREFIX=""
config/app.php
以下の箇所のコメントを外す(抜粋)
App\Providers\BroadcastServiceProvider::class,
ブロードキャストするイベントクラス
以下のファイルを追加
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class PublicEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $item;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($item)
{
$this->item = $item;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('public-event');
}
public function broadcastWith()
{
return [
'item' => $this->item,
];
}
}
routes/web.php
ルーティング設定を追加(抜粋)
Route::get('send', 'NotificationController@send')->name('notification.send');
イベント呼び出し処理
NotificationControllerを作成し、sendメソッドを追加(抜粋)
public function send(Request $request)
{
$message = 'テストメッセージ配信';
$data = ['id' => time(), 'message' => $message];
event(new \App\Events\PublicEvent($data));
return view('notification.complete');
}
環境構築(受信側)
NuxtJS側でメッセージを受け取る設定を行う。
package.json
ライブラリを追加(抜粋)
{
"dependencies": {
"socket.io-client": "^2.3.0"
},
"devDependencies": {
"@nuxtjs/laravel-echo": "^1.1.0"
}
}
nuxt.config.js
ech-serverとの通信設定を行う(抜粋)
buildModules: [
[
'@nuxtjs/laravel-echo',
{
broadcaster: 'socket.io',
host: 'http://localhost:6001',
}
],
pages/index.vue
受信設定を行う(抜粋)
async mounted() {
this.$echo.channel("public-event")
.listen("PublicEvent", e => console.log(e));
},
npm run devコマンドで起動し、php側でメッセージ配信をすると、consoleに出力されることを確認する。