Laravelでキューを使ってみたかったんだけど、世のドキュメントが公式も非公式もやたら小難しく、分かりづらかったので時間がかかった。
Redisは使わずに、database
ドライバの最小構成でキューを試していく。
キュー[queue]・キューワーカー・ジョブとは(概要[CHATGPT])
Laravelのキュー(queue)、キューワーカー(worker)、およびジョブ(job)について簡潔に説明します。
キュー(queue):
キューはタスクやジョブを非同期に処理する仕組みです。
特定の処理を直ちに実行せず、後で実行するためのキューにタスクを入れることができます。
ジョブ(job):
ジョブはキューに入れられる実際の処理単位です。
通常、時間のかかる処理や非同期に実行されるべき処理をジョブとして定義します。
キューワーカー(worker):
キューワーカーは、キューに入れられたジョブを非同期に実行するプロセスです。
キューワーカーはジョブを取り出し、実行し、次々にキュー内のジョブを処理します。
簡単な例を挙げると、以下のような流れです:
Laravelアプリケーション内で、時間のかかる処理をキューに追加したい場合、その処理をジョブとして定義します。
ジョブはキューにプッシュされ、即座にレスポンスを返すことができます。
キューワーカーがバックグラウンドで動作していると、そのキューからジョブを取り出し、非同期に処理します。
この仕組みにより、ユーザーは待たずにアプリケーションを使用でき、時間のかかる処理はバックグラウンドで実行されます。
本筋
サクッとLaravel Queueデビューしていく
準備編
- 前提
- 一般的なLaravelプロジェクトが作成済。
- (筆者の環境はLaravel 9)
database
ドライバでキューを管理するためには、プロジェクトにjobs
データベーステーブルが必要となる。
php artisan queue:table
php artisan migrate
次に、config/queue.php
ファイル内部で参照されている.env
のQUEUE_CONNECTION
項目をsync
からdatabase
に変更しておく。
//...
#QUEUE_CONNECTION=sync
QUEUE_CONNECTION=database
//...
続いてジョブクラスを作成していく。
ジョブクラスには実際の重たい処理を記述する。
※Artisan::queue()
を使えば必須ではないが、普通に不便で分かりづらいので作成していく。
php artisan make:job TestJob
コマンドを実行すると、プロジェクトにApp\Jobs
配下にTestJob
クラスが作成される。
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class TestJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* ジョブを試行する回数。
*
* @var int
*/
public $tries = 3;
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
// The Heavy Process
}
public function failed($exception)
{
//Log::channel('laravel')->error($exception);
}
}
これで処理の記述は完了したが、動作させるためには、実際のジョブを実行する為のキューワーカーを起動させる必要がある。
キューワーカー起動
#20分以内に1つのジョブが終わらない場合、エラーとなる。
php artisan queue:listen --timeout=1200
キューワーカーの注意点として、プロジェクトにソースコードの変更があった場合にもキューワーカーは変更を感知しない。
ソースコードを反映させたい場合は次のコマンドで、キューワーカーの再起動を行う必要がある。
php artisan queue:restart
実際にジョブを実行
別プロセスでキューワーカが動いてくれているので、メインのプロセスからジョブをキューへ入れてみる。
use App\Jobs\TestJob;
//...
// ジョブをキューに割り当てる
TestJob::dispatch()
// 10秒遅れて起動
->delay(now()->addSeconds(10));
dispatchは仕事を割り当てるとかの意味らしい。
解説
dispatchすると、ジョブがjobs
テーブルに挿入される。
キューワーカーは、折を見て(自分が暇なときに)jobs
テーブルから仕事を見つけてきて、実行する。
つまり、キューワーカーはメインプロセス(API応答や、リソース描画)とは完全に別なチャンネルで動いているので、非同期なアクションを実現できる。
ジョブが成功すると、jobs
テーブルからレコードが削除される。
ジョブが失敗した場合は、failed_jobs
テーブルに記録される。
※failed_jobsテーブルはある程度のverのLaravelからはマイグレーションが初期搭載されている。
おまけ
public function retryUntil()
の使い道がいまひとつわからなかった。
コマンドでキューワーカーを動かす際に --timeout=1200
と指定しないと反映されないように見える。
参考