この記事は Laravel Advent Calendar 2019 6日目の記事です
イベントの発行、イベントリスナのキュー投入、投入したジョブの実行、といった機能が Laravelでは提供されていますが、キューに積まれるジョブの実行単位を間違え、失敗してしまったことが最近あったので、本記事ではあらためてイベント・ジョブ・キューについて書いてみようと思います
1. イベント・リスナーとは
-
何かしらの動作や変更が発生した際に発信される処理のこと
-
イベントが発生し検出されると、リスナーと呼ばれるイベントに対応する処理が実行されるようになっている
-
リスナーの処理は、キュー(Queue)に積んで非同期で実行することができる
-
ドキュメント イベント 6.x Laravel
2. ジョブ(Job)・キュー(Queue)とは
-
キューは待ち行列のこと。非同期で処理を実行するときの処理待ちの処理のリスト
-
処理の実行単位のことをジョブという
-
ドキュメント キュー 6.x Laravel
3. ワーカー(Worker)
-
Queue(キュー)に積まれたジョブ(Job)は、非同期で順次処理されていくが、その時に非同期でジョブを実行してくれるプログラムのことをワーカー(Worker)という
-
ジョブの実行が失敗した場合のリトライ処理などもワーカー(Worker)がやってくれる
4. 失敗したこと
-
サービス利用全ユーザーにメールを送信したい場合、以下のようなコードを書いていた
-
ワーカー(Worker)は最大試行回数を10回としていて、失敗しても最大10回リトライされるようになっていた
-
イベントの発行(
event
ヘルパにイベントのインスタンスを渡すとイベントを発行することができる)
/**
* メール通知
* @param $notification
*/
private function triggerEvent($notification)
{
// メール送信用にEvent登録する
event(new Notification($notification));
return;
}
- リスナーの処理
class UserEventSubscriber implements ShouldQueue
{
public function subscribe(Dispatcher $dispatcher)
{
}
public function handle(Notification $event)
{
$event->send();
}
}
-
$event->send()
の処理
public function send(): void
{
// ユーザーを全取得
$users = User::all();
// メール通知
foreach ($users as $user) {
\Mail::to($user->email)->queue(new EventMail($this->notification));
}
}
-
上記コード例の問題点は、1人でもメール送信に失敗したユーザーが存在した場合、リトライされ成功した残りのユーザーに対しても、再通知されるようになっていたこと
-
キューに積まれていく、イベントリスナの処理の中で、キューに積まれていくメール送信の処理があり、失敗した時のリトライする単位を、送信に失敗したメール単位だと勘違いしてしまっていた
-
正しくは、イベントで呼び出されたリスナ単位でキューに積まれるのが正しかったです
リスナがイベントのために呼び出されると、Laravelのキューシステムを使い、イベントデスパッチャーにより自動的にキューへ投入されます
まとめ
- イベント、ジョブ(Job)、キュー(Queue)の仕組みは、コード自体の変更箇所以外に、インフラ、ワーカー(Worker)の設定などを正しく認識していないと、ちょっとした勘違いで大きなミスになってしまうと思った
- すごく初歩的なところで失敗したことと、ドキュメントに書いてあるようなことをそのまま紹介してしいる記事になってしまったのですが、イベント、ジョブ(Job)、キュー(Queue)の仕組みについて勉強になったのはよかった
- 次はこの仕組みを提供してるLaravelのコードを自体を読んで、どういう仕組みで動いてるか理解できるようにしたい