処理(ここではJob)を分けて別プロセスで動かすことができる機能。
ひときわ重い処理など別プロセスで動かして気が付いたら出来ている、ということが出来るとうれしいことがある。
逆にすぐに結果を返してほしい場合には向かない。(syncという設定ですぐに実行もできるがデバッグ以外の用途使う理由がないと思う。)
良く例に上がる用途としてPDF作成やメール。
というわけでLaravelのキューの実装について。
(ここでは接続先はデータベースです。)
やることは
Job追加先の設定
追加先はいろいろ選べます。
データベース、Beanstalkd、Amazon SQS、Redis、同期実行。
詳細な設定はconfig/queue.phpで行いますが、.envでQUEUE_CONNECTIONを設定を切り替えることもできます。
データベースに追加する場合テーブルを追加します。
php artisan queue:table php artisan migrate
またキューの接続方法の設定も行います。
.env
QUEUE_CONNECTION=database
Jobクラス作成
php artisan make:job ProcessJob
class ProcessJob implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; // ジョブの実行 public function handle(){} }
handleメソッドの処理が実際に実行される処理となります。
Jobをキューに追加
追加方法はたくさんあるので詳細はドキュメントを見た方が良いかも。
// 一番シンプルなケース ProcessJob::dispatch($params); // 遅延実行 ProcessJob::dispatch($params)->delay(now()->addMinutes(10)); // 同期実行 ProcessJob::dispatchNow($params); // クロージャーによるキュー実行 dispatch(function () use ($processor, $params) { $processor->doSomething($params); });
入れるキューを変更する方法
ProcessJob::dispatch($params)->onQueue('mail');
接続先を変更する方法
ProcessJob::dispatch($params)->onConnection('sqs');
キューの実行
キューの実行は別プロセスで実行します。
LaravelのドキュメントではSupervisorというLinuxで動くプロセスモニタが紹介されています。
手動かcronかタスクスケジュールであれば以下のコマンドでも動かせます。
php artisan queue:work
いろいろオプションがあるのでこれでもドキュメントで自分に合ったものを探してください。
// 接続とキューの指定 php artisan queue:work redis --queue=emails // ジョブを一つ処理する php artisan queue:work --once // キューされた全てのジョブを処理し、終了する php artisan queue:work --stop-when-empty // 優先度順に処理 php artisan queue:work --queue=high,low // ワーカタイムアウト php artisan queue:work --timeout=60 // 新しく処理するジョブが存在しない時に、どの程度「スリープ」するか php artisan queue:work --sleep=3
Job失敗時の対処
失敗した場合テーブルに保存することができます。
php artisan queue:failed-table php artisan migrate
ただし、実行する際–triesを指定しないと無限に繰り返すので設定は必須かと。
php artisan queue:work redis --tries=3
ジョブが失敗したときには先ほど定義したジョブクラスに失敗処理を記述することができます。
class ProcessJob implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; // 失敗ジョブのエラー処理 public function failed(Exception $exception){} }
これとは別にジョブが失敗したときのイベントを追加できます。
これはプロバイダーに登録しておくのが良いタイミングのようです。
use Illuminate\Support\Facades\Queue; use Illuminate\Queue\Events\JobFailed; class AppServiceProvider extends ServiceProvider { /** * 全アプリケーションサービスの初期処理 * * @return void */ public function boot() { Queue::failing(function (JobFailed $event) { // $event->connectionName // $event->job // $event->exception }); } }
ジョブの失敗リストをみることもでき、ここからさらに失敗したものを再実行もできます。
php artisan queue:failed +----+------------+---------+---------------------+---------------------+ | 4 | database | default | App\Jobs\ProcessJob | 2019-07-24 02:37:43 | | 3 | database | default | App\Jobs\ProcessJob | 2019-07-24 02:36:56 | | 2 | database | default | App\Jobs\ProcessJob | 2019-07-24 02:35:39 | | 1 | database | default | App\Jobs\ProcessJob | 2019-07-24 02:33:38 | +----+------------+---------+---------------------+---------------------+ // id=2を実行する php artisan queue:retry 2 // 失敗したジョブをすべて実行する php artisan queue:retry all // id=1を消す php artisan queue:forget 1 // 失敗ジョブをすべて消す php artisan queue:flush
おまけ
ジョブの実行前後で実行するイベントを追加できます。ログや経過時間などを出力させておくのに便利かも。
class AppServiceProvider extends ServiceProvider { public function boot() { Queue::before(function (JobProcessing $event) { // $event->connectionName // $event->job // $event->job->payload() }); Queue::after(function (JobProcessed $event) { // $event->connectionName // $event->job // $event->job->payload() }); } }