Laravelのイベント・リスナを分割する。
データベースを使ってイベント・リスナを分割する。
データベース(SQL)を使って、イベントをキューに登録し、queue:work でリスナがイベントを拾って動作させる。
データベースにイベント発生を登録してジョブキューとワーカーにする。イベントハンドラとイベントを動作タイミングを分離してレスポンスを高速化したり、後でいいものは後ろに回す。
プロジェクトを作る
まず、プロジェクトを作成して実験環境を整える。
composer create-project laravel/laravel database-listener-sample cd database-listener-sample sed -i config/app.php -e 's|UTC|Asia/Tokyo|' sed -i .env -e 's/DB_/#DB_/' -e '/mysql/i DB_CONNECTION=sqlite' php artisan migrate ## キューをDBに入れる。 sed -i .env -e 's/QUEUE_CONNECTION=sync/QUEUE_CONNECTION=database/'
イベントとリスナを作る
ここで作ったリスナが、php artisan queue:work
でリスナを受け取って実行する。
また、イベントを発火させるコマンドを作る。
php artisan make:event MyEvent php artisan make:listener MyListener php artisan make:command AddJob
コマンドからイベントを発火させる部分
ここでは、手動でイベントを発火させるコードを記入しておく。
<?php namespace App\Console\Commands; use App\Events\MyEvent; use App\Listeners\MyListener; use Illuminate\Console\Command; use Illuminate\Support\Facades\Event; class AddJob extends Command { protected $signature = 'app:add-job'; public function handle() { Event::listen(MyEvent::class,MyListener::class); Event::dispatch(new MyEvent()); } }
イベント
ここでは、特に何も書かない。イベントとしてクラスを定義するだけ
<?php namespace App\Events; use Illuminate\Queue\SerializesModels; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Broadcasting\InteractsWithSockets; class MyEvent { use Dispatchable, InteractsWithSockets, SerializesModels; }
リスナ定義
リスナはイベント発火時に動作をする。イベントはデータベースから引き取るためにconnection
を入れる。
<?php namespace App\Listeners; use App\Events\MyEvent; use Illuminate\Contracts\Queue\ShouldQueue; class MyListener implements ShouldQueue { public $connection = 'database'; public function __construct() {} public function handle( MyEvent $event ):void { dump([$this, $event]); } }
DBの作成
キューをためておくテーブルを作る。
php artisan queue:table php artisan migrate ## または php artisan migrate:fresh
準備完了
ここまでで、キューテーブルをつくり、テーブルでイベントの受け渡しをするListernを作り、イベントを発火させるコマンドを作った。
実験
コマンドを実行して、イベント発火する
php artisan app:add-job
ここでは、イベントを発火させるだけ。
ジョブの登録を確認。
イベントはジョブとしてキューに貯まるはずので、それを確認する。
sqlite3 database/database.sqlite 'select * from jobs;'
-- Loading resources from /Users/takuya/.sqliterc id queue payload attempts reserved_at available_at created_at -- ------- ------------------------------------ ---- ----------- ------------ ---------- 1 default {..."App\\Listeners\\MyListener",... 0 1707798204 1707798204
リスナを動作させる。
キューに溜まったイベントをリスナで動かす。
php artisan queue:work
コマンド実行すると、ワーカーが、キューを読み込んで、リスナに処理をやらせてくれる。
INFO Processing jobs from the [default] queue. 2024-02-13 03:46:10 App\Listeners\MyListener ......... RUNNING 2024-02-13 03:46:10 App\Listeners\MyListener ......... 8.69ms DONE
あとは、画面を見ながら、イベントを発火せてリスナが処理をするのを眺めていれば、処理機構の枠組みがわかってくる。
覚えるポイント
キューを使ってイベント・リスナの処理を分割するときのポイント。
リスナをデータベースに入れる。
$connection = 'database'
を使ってイベント発火し、リスナに割り当てる(dispatch)するとき、実行せずにデータベースに放り込む。
<?php class MyListener { public $connection = 'database'; }
リスナを「動作可能にする」
laravel ではClass::handle()
やClass::__invoke()
を用意すれば、クラスを「実行可能」と定義できる。
<?php class MyListener implements ShouldQueue { public function handle( ...); }
イベント発火の方法
次はほぼ同じ。
Event::dispatch(new MyEvent()); event(new MyEvent());
イベントとリスナを紐付ける方法
サービスプロバイダで定義してもいいし、Event::listen
を使ってもいい。
サービスプロバイダを使うときはEventServiceProvider
にかくか、AppServiceProvider#boot()
にかく。
Evnet:listen
はFacedeに定義されている。\Illuminate\Support\Facades\Event
がクラス名である。
キューをデータベースに入れる。
sed -i .env \ -e 's/QUEUE_/#QUEUE_/' \ -e '/CONNECTION=sync/i QUEUE_CONNECTION=database'
envに書かずに、動かすには、自分で書くしかない。
データベースに入れ設定を先に書いておかないと、queue:work によるキュー動かないので注意。
2024-05-30
下書きから更新。