Laravel の Events/Listeners で非同期処理を実装する方法

Laravel の Events/Listeners で非同期処理を実装する方法 Laravel
記事内に広告が含まれています。

Laravel の Events/Listeners(イベント/リスナ)を使用して非同期処理を実装していきます

具体的には、Events 発行後 Listeners で検知し、Listeners の処理を Queue に投入して非同期で処理を実行させます。

Laravel の Events/Listeners で非同期処理を実装する方法

Events/Listeners の作成と登録を行う

Events/Listeners(イベント/リスナ)の作成と登録をしていきます。

app/Providers/EventServiceProvider.php

    /**
     * The event listener mappings for the application.
     *
     * @var array<class-string, array<int, class-string>>
     */
    protected $listen = [
        "App\Events\SampleEvent" => [
            "App\Listeners\SampleListener"
        ]
    ];

$listen というメンバ変数に、「キー:SampleEvent、値:SampleListener」を設定。その後、下記コマンドを実行することで、定義したファイルが生成されます。

php artisan event:generate

app/Events/SampleEvent.php

<?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 SampleEvent
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}

app/Listeners/SampleListener.php

<?php

namespace App\Listeners;

use App\Events\SampleEvent;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class SampleListener
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  \App\Events\SampleEvent  $event
     * @return void
     */
    public function handle(SampleEvent $event)
    {
        //
    }
}

make:eventmake:listener といった Artisan コマンドを利用して、個々に Event と Listener を作成することも可能です。その場合は以下のようなコマンドを実行してあげます。

php artisan make:event SampleEvent
php artisan make:listener SampleListener --event=SampleEvent

Event を発行する

続いて Event(イベント)の発行です。Event の発行に関しては、event 関数を用いれば簡単に Event を発行することができます。

app/Http/Controllers/SampleController.php

<?php

namespace App\Http\Controllers;

use App\Events\SampleEvent;
use Illuminate\Http\Request;

class SampleController extends Controller
{
    /**
     * Handle the incoming request.
     *
     * @param string $sample
     */
    public function __invoke(string $sample)
    {
        // $sampleには適当な文字列が入っているとします
        event(new SampleEvent($sample));
    }
}

Event と Listener に処理を書いていく

SampleController が呼ばれると __invokeメソッド内の event 関数が実行されますが、SampleEvent と SampleListener には何も処理を書いていないので、こちらに処理を書いていきます。

まずは SampleEvent から。

app/Events/SampleEvent.php

<?php

namespace App\Events;

class SampleEvent
{
    /**
     * Sample
     * 
     * @var string
     */
    public $sample;
    
    /**
     * Create a new event instance.
     *
     * @param string $sample
     * @return void
     */
    public function __construct(string $sample)
    {
        $this->sample = $sample;
    }

    /**
     * Get Sample
     *
     * @return string
     */
    public function getSample()
    {
        return $this->sample;
    }
}

Event クラスでは、Listener クラスで利用するデータ等の保持を記載しておきます。broadcastOn メソッドは使用しないので削除しました。

app/Listeners/SampleListener.php

<?php

namespace App\Listeners;

use App\Events\SampleEvent;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class SampleListener
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param SampleEvent  $event
     * @return void
     */
    public function handle(SampleEvent $event)
    {
        // $event->getSample()のようにEvent側の処理を呼ぶことできる
        // 何らかの処理を記載
    }
}

Listeners に関しては、handle メソッド内に処理を書いていきます。今回は Sample ということで具体的な処理内容については記載していません。

Listener の処理を Queue に投入して非同期で処理を実行させる

現在の状態だと、同期処理で実行されるので、Listener の処理を Queue に投入して非同期で処理を実行させる方法について書いていきます。

Queue の設定を行う

まずは Queue の設定から。今回は Queue ドライバとして DB を利用するので、QUEUE_CONNECTION に database を指定します。

QUEUE_CONNECTION=database

jobs・failed_jobs テーブルの作成を行う

続いて Listener の処理を保存するための jobs テーブルと、失敗した job を格納するための failed_jobs テーブルを作成します。

failed_jobs テーブルに関しては、Laravel をインストールした際に migration ファイルが用意されているかと思うので、そのファイルを使用します。

php artisan queue:table
php artisan migrate

キューワーカも起動させておきましょう。

php artisan queue:listen

キューワーカに関しては、supervisor でプロセス監視をしておくと良いです。

Listener で ShouldQueue インターフェースを継承する

Listener の処理を Queue に投入し、非同期で処理を実行するため、SampleListener クラスに ShouldQueue インターフェースを継承させます。

app/Listeners/SampleListener.php

class SampleListener implements ShouldQueue

また、Listner の処理の送信先となる Queue 名や、処理開始までの実行時間も指定することができます。

app/Listeners/SampleListener.php

<?php

namespace App\Listeners;

use App\Events\SampleEvent;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class SampleListener implements ShouldQueue
{
    /**
     * 接続名
     * 
     * @var string
     */
    public $connection = "database";

    /**
     * キュー名
     * 
     * @var string
     */
    public $queue = "sample";

    /**
     * 処理開始されるまでの時間(秒)
     * 
     * @var int
     */
    public $delay = 20;
}

失敗した Job の処理を行う

Queue に投入した処理が失敗した場合、Listener 上の failed メソッドが呼ばれます。なので、ここに失敗通知を送る処理などを記載しておくと良いでしょう。

app/Listeners/SampleListener.php

    /**
     * 失敗したJobの処理
     *
     * @param SampleEvent $event
     * @param Exception $exception
     */
    public function failed(SampleEvent $event, Exception $exception)
    {
        // 失敗した内容をメール通知する処理などを記載
    }

Queue ファサードの before や after、failing メソッドを使用して、キュー投入したジョブが処理される前後や失敗時に実行するコールバックを指定することもできます。

まとめ|Laravel の Events/Listeners で非同期処理を実装する方法

ここまで、「Laravel の Events/Listeners で非同期処理を実装する方法」について書いてきました。

流れとしては、Events 発行後 Listeners で検知して、Listeners の処理を Queue に投入して非同期で処理を実行させるというもの。

Listeners の処理を Queue に投入して処理を実行させる部分に関しては、あまり情報が落ちていなかったので実装するのに一苦労しました

Laravel関連のおすすめ本・Udemy講座

コメント

タイトルとURLをコピーしました