Laravel+Redis+NuxtJSでブロードキャストを行う

Laravel+Redis+NuxtJSでブロードキャストを行う

RedisのPub/Sub機能を使って、Laravel の管理画面から、NuxtJSにリアルタイム配信を行ったときのメモを残す。

実行環境

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に出力されることを確認する。

参考リンク

Web技術カテゴリの最新記事