【Laravel】キューとジョブの使い方入門|Queue・Job・Workerの仕組みと実装方法

HTTP リクエストの中でメール送信、帳票生成、外部 API 呼び出しを抱え込むと、ユーザーは画面の完了を待たされます。処理が伸びたときはタイムアウトや二重送信も起きやすくなり、失敗時の再実行もコントローラ内だけでは扱いづらくなります。

Laravel の Queue / Job / Worker は、この種の重い処理を「あとで別プロセスが実行する仕事」として切り出すための仕組みです。この記事では、database ドライバを使った最小構成を軸に、Job の作成、キューへの投入、Worker の起動、よくある失敗を整理します。

細かな API は Laravel のメジャーバージョンで変わることがあります。手元の composer.jsonlaravel/framework に合わせ、Laravel 公式ドキュメントの Queues 章の該当バージョンを開いて照合すると再現しやすいです。

はじめに

この記事では、Laravel のキューを初めて実装する場面を想定し、次の範囲を扱います。

  • Queue / Job / Worker の役割
  • database ドライバで動かす最小構成
  • Job の作成、dispatch、Worker の起動
  • 実務でハマりやすい注意点と失敗例

背景:Queue・Job・Worker の役割

Queue / Job / Worker は、次のように役割が分かれます。

用語役割
QueueJob を一時的に置く待ち行列defaultemailsreports
JobWorker が実行する処理単位メール送信、帳票生成、外部 API 呼び出し
WorkerQueue から Job を取り出して実行するプロセスphp artisan queue:work

たとえるなら、Queue は郵便受け、Job は封筒に入った依頼、Worker は封筒を取り出して処理する配達員のような位置づけです。

Laravel の設定は主に config/queue.phpQUEUE_CONNECTION で制御します。Connections vs. Queues では、Redis や database などの接続先と、接続先の中にあるキュー名が別概念として説明されています。

実装と検証

database ドライバの準備

ローカルで最小構成を試すなら、database ドライバは挙動を追いやすい選択肢です。Laravel のバージョンによって生成コマンドの細部は異なるため、Driver Prerequisites を確認してください。代表的には、ジョブ保存用のテーブルを作成してマイグレーションします。

php artisan queue:table
php artisan migrate

.env ではキュー接続を指定します。

QUEUE_CONNECTION=database

Redis や Amazon SQS を使う場合は、それぞれの接続設定やドライバ前提が追加されます。この記事では、まず database ドライバで流れを確認します。

Job を作成する

Artisan で Job クラスを生成します。

php artisan make:job SendWelcomeMail

ShouldQueue を実装した Job は、dispatch されたあとキューに積まれます。Worker が取り出したときに実行されるのが handle メソッドです。

<?php

namespace App\\Jobs;

use App\\Models\\User;
use Illuminate\\Contracts\\Queue\\ShouldQueue;
use Illuminate\\Foundation\\Queue\\Queueable;
use Illuminate\\Support\\Facades\\Mail;

class SendWelcomeMail implements ShouldQueue
{
    use Queueable;

    public function __construct(
        public User $user,
    ) {}

    public function handle(): void
    {
        Mail::to($this->user->email)->send(new \\App\\Mail\\WelcomeMail($this->user));
    }
}

この例では WelcomeMail は事前に作成済みの Mailable クラスとします。まだ作っていない場合は、メール本文の実装を別途用意してください。

Eloquent モデルを Job のコンストラクタに渡すと、キュー投入時にモデル全体ではなく識別子を中心にシリアライズされます。この挙動やリレーションの扱いは Queued Relationships に注意点があります。

Job をキューに積む

コントローラやサービスから dispatch します。

use App\\Jobs\\SendWelcomeMail;

SendWelcomeMail::dispatch($user);

特定のキュー名へ積みたい場合は onQueue を使います。

SendWelcomeMail::dispatch($user)->onQueue('emails');

「今すぐ同期的に実行したい」場面では dispatchSync もあります。ただし、同期実行にすると HTTP リクエスト中に処理が戻るため、キューへ逃がす目的と合っているか確認が必要です。

Worker を起動する

Job を dispatch しただけでは、Worker が動いていない限り処理は進みません。開発環境では次のコマンドで Worker を起動できます。

php artisan queue:work

複数のキュー名を使う場合は、優先順を指定できます。

php artisan queue:work --queue=high,default

本番では Worker をターミナルで手動起動したままにせず、Supervisor などのプロセス管理と組み合わせるのが一般的です。Laravel 公式ドキュメントにも Supervisor Configuration の例があります。

Worker は長時間動き続けるプロセスです。コードをデプロイしたあと、古いコードを読んだ Worker が残らないように、公式ドキュメントでは queue:restart による安全な再起動が説明されています。

php artisan queue:restart

失敗時の確認と再実行

失敗ジョブを扱うには、失敗ジョブ用のテーブルや設定が必要です。バージョンによりコマンドや前提が異なるため、Dealing With Failed Jobs を確認してください。

代表的な確認コマンドは次のようなものです。

php artisan queue:failed
php artisan queue:retry all

再実行は便利ですが、外部 API 呼び出しや決済連携のように副作用がある Job では、冪等性を設計してから使う必要があります。

実装時の注意点

Job に大きなオブジェクトや不要なリレーションを詰め込むと、ペイロードが膨らみます。必要な ID だけを渡し、handle 内で最新の状態を取り直すほうが読みやすい場面もあります。

運用時は、少なくとも Worker のログ、失敗ジョブ、ジョブの滞留数を確認対象に入れると原因を追いやすくなります。database ドライバなら jobs テーブルの件数も、ローカル検証では分かりやすい手がかりになります。

失敗例:Job は作ったのに Worker を起動していなかった

筆者が初めて Laravel のキューを導入した現場では、登録完了メールを Job 化したあと、ローカル環境で「メールが飛ばない」と調査したことがあります。コード上は SendWelcomeMail::dispatch($user) まで通っており、例外も出ていませんでした。

原因は単純で、QUEUE_CONNECTION=database にしたまま php artisan queue:work を起動していませんでした。Job は jobs テーブルに積まれていましたが、取り出す Worker がいないため、処理されないまま残っていました。

この失敗は「dispatch は実行予約であり、実行そのものではない」と捉えれば避けやすくなります。

そのときは、dispatch 後に jobs テーブルを確認し、レコードが残り続けていることから Worker 未起動に気づきました。次に Worker のログを見て、処理が一度も取り出されていないことを確認しました。

同じ切り分けをテストで行う場合は、Queue Fake を使う方法もあります。

学び:Queue はコードだけでなく運用も含めて設計する

Queue / Job / Worker は、重い処理を外に逃がすだけの機能ではありません。Worker の起動、監視、失敗時の再実行、デプロイ時の再起動まで含めて設計して、はじめて安定して使えます。

小さく始めるなら、まず database ドライバで Job が積まれ、Worker が取り出し、失敗時にどう見えるかを一通り確認するのがよいです。そのうえで Redis や SQS など、本番構成に合うドライバを検討すると理解がつながります。

まとめ

  • Queue は Job を置く待ち行列、Job は処理単位、Worker は Job を取り出して実行するプロセスである。
  • dispatch だけで処理は進まないため、queue:work などで Worker を動かす必要がある。
  • 本番では Worker の常駐、再起動、失敗ジョブの確認、冪等性まで含めて設計する。

次に試せること

  1. QUEUE_CONNECTION=database で Job を 1 つ作り、dispatch 前後で jobs テーブルの変化を確認する。
  2. php artisan queue:work --queue=high,default を試し、キュー名の優先順を体感する。
  3. handle 内で例外を投げる Job を作り、queue:failedqueue:retry の挙動を検証する。

Source

LaravelLaravel

Posted by 千原 耕司