dispatch — ジョブをキューへ投入するヘルパ

helper
  • カテゴリ: helper
  • 掲載バージョン: Laravel 12・PHP 8.4
  • 名前空間 / FQCN / コマンド: dispatch()(グローバル関数)
  • 関連: Bus::dispatch / dispatch_sync / php artisan queue:work / ジョブクラスの dispatch() メソッド
  • 変更履歴: Laravel 5系から存在。Laravel 8 以降は仕様ほぼ据え置き(ジョブのチェーンやディレイ指定など PendingDispatch 経由の機能が充実)。

要点(TL;DR)

  • 何に使うか:キュー用のジョブやコマンドバスの「コマンド」を、Laravelのキューへ投入する。
  • 最低限の使い方dispatch(new App\Jobs\SendWelcomeMail($user));
  • よくある罠
    • キュー接続が sync のままで「実は同期実行」になっている
    • queue:work を動かしておらず、いつまで経ってもジョブが処理されない
    • ShouldQueue を実装しておらず、キューに積まれずその場で実行されてしまう

概要

dispatch は、Laravel が提供するグローバルヘルパ関数で、指定したジョブをキューへ投入する入り口です。
App\Jobs\* に定義したジョブクラスや、ShouldQueue を実装したクラスを渡すと、設定されたキュー接続(database / redis / sqs など)に積まれます。
ジョブクラス側の ::dispatch() と機能はほぼ同じで、関数スタイルで書きたいときや、Facade に依存したくない場面で使われます。

構文 / シグネチャ

/**
 * ジョブ/コマンドをバス経由でディスパッチする
 */
function dispatch(object $job): mixed;

引数

引数必須既定値説明
$jobobjectなしディスパッチするジョブ/コマンド。通常は App\Jobs\* のインスタンス。ShouldQueue 実装でキューへ積まれる

戻り値

  • 通常は Illuminate\Foundation\Bus\PendingDispatch もしくはジョブの戻り値(同期実行時)
  • PendingDispatch 経由で ->onQueue(), ->delay() などをチェーン指定可能

例外 / 副作用

  • キュー接続の設定が不正な場合、InvalidArgumentException などの例外
  • ドライバが sync 以外の場合、キューバックエンド(DB / Redis / SQS 等)にレコードやメッセージを追加
  • sync 実行や ShouldQueue 未実装時は、その場で handle() が実行され、その中で発生した例外がそのままスローされる

使用例

最小例

ユーザー登録後にウェルカムメール送信ジョブをキューへ投入する例です。

<?php

use App\Jobs\SendWelcomeMail;
use App\Models\User;

Route::post('/register', function () {
    $user = User::create([
        'name'  => request('name'),
        'email' => request('email'),
        'password' => bcrypt(request('password')),
    ]);

    // キューへジョブを投入
    dispatch(new SendWelcomeMail($user));

    return response()->json(['message' => 'Registered'], 201);
});

ジョブ側(ざっくり):

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\User;
use Illuminate\Support\Facades\Mail;

class SendWelcomeMail implements ShouldQueue
{
    use Queueable, InteractsWithQueue, SerializesModels;

    public function __construct(private User $user)
    {
    }

    public function handle(): void
    {
        // 実際のメール送信処理
        Mail::to($this->user->email)->send(/* ... */);
    }
}

実務例:重いレポート生成を非同期化

レポート生成とS3保存のような重い処理を、キューに逃がす例です。

<?php

use App\Jobs\GenerateSalesReport;
use Illuminate\Http\Request;

Route::post('/reports/sales', function (Request $request) {
    $year = (int) $request->input('year');

    // 処理は非同期。レスポンスはすぐ返す
    dispatch(new GenerateSalesReport($year))
        ->onQueue('reports')   // 専用キュー
        ->delay(now()->addMinutes(1)); // 少し遅延させる

    return response()->json([
        'message' => 'レポート生成を受け付けました。',
    ]);
});

ジョブ側では handle() 内で DB 集計 → CSV 生成 → S3 保存などを行い、完了後に通知を送るようにします。

よくある落とし穴・注意

  • 非同期になっていない
    • .envQUEUE_CONNECTION=sync のままだと、その場で handle() が実行されます。
    • 本番で非同期化したい場合は、databaseredis などの接続を設定し、queue:work を常駐させます。
  • ShouldQueue を付け忘れる
    • ジョブクラスが ShouldQueue を実装していないと、「ジョブ」ではなく「コマンド」としてその場で実行されます。
  • ワーカーを動かしていない
    • php artisan queue:work(または supervisor 等)が動いていないと、いくら dispatch() しても処理されません。
  • シリアライズできないプロパティ
    • クロージャや外部リソース(PDO、ストリーム)をプロパティに持つと、Serialization of 'Closure' is not allowed などのエラーに繋がります。
    • 原則として、IDなど最小限の値だけをジョブに渡し、handle() 内で再取得するのが安全です。

代替・関連APIとの比較

  • ジョブクラスの ::dispatch()
    • 例: SendWelcomeMail::dispatch($user);
    • 実質的に dispatch(new SendWelcomeMail($user)) と同じ。
    • 「どのクラスのジョブか」が明確なので、実務ではこちらがよく使われます。
  • Bus::dispatch()
    • 例: Bus::dispatch(new SendWelcomeMail($user));
    • Facade ベースで書きたい時や、バッチ/チェーンと合わせて使う場合に選択。
  • dispatch_sync() / dispatch_now()
    • 強制的に「今すぐ実行」したいときに使用(テストや緊急用途)。
    • 非同期前提なら、通常は dispatch() を使い、同期はキュー接続を sync にするほうが設計としてはわかりやすいです。
  • イベントの event()
    • event() はイベントリスナを起動する API で、ジョブキューとは別物。
    • 「時間のかかる処理をバックグラウンドに逃がす」目的なら dispatch()
      「状態変化に応じて複数の処理をトリガーしたい」なら event() という使い分けが基本です。

テスト例(Pest)

dispatch() がジョブをキューへ投入しているかを確認する最小テストです。

<?php

use App\Jobs\SendWelcomeMail;
use App\Models\User;
use Illuminate\Support\Facades\Queue;

it('dispatches welcome mail job', function () {
    Queue::fake();

    $user = User::factory()->create();

    dispatch(new SendWelcomeMail($user));

    Queue::assertPushed(SendWelcomeMail::class, function ($job) use ($user) {
        return $job->user->is($user);
    });
});

トラブルシュート(エラー別)

症状/エラー原因対処
ジョブがいつまで経っても実行されないQUEUE_CONNECTION がキュー向けに設定されていても、php artisan queue:work が動いていないキュー接続を確認し、本番では supervisor などで queue:work を常駐させる
実際には同期処理になっていた.envQUEUE_CONNECTION=sync のまま非同期化したい環境では databaseredis など適切なドライバへ変更
Serialization of 'Closure' is not allowedジョブのプロパティにクロージャやシリアライズ不可なオブジェクトを持たせているプロパティには ID やスカラ値、Eloquent モデル程度に留め、handle() 内で必要なオブジェクトを再生成する
InvalidArgumentException: No connector for [] などキュードライバ関連の例外config/queue.php の設定ミス、または .envQUEUE_CONNECTION が存在しない接続名設定ファイルの connections 配列に対象接続が定義されているか確認し、キャッシュを php artisan config:clear でクリア

参考リンク

レン (Wren)

こんにちは。レンです。

Laravelのコードの森に住んでいる、小さな案内役です。
ルーティングの枝やクラスの影を歩きながら、コードの流れや仕組みを眺めています。

このサイトでは、Laravelの基本から実装のコツまで、開発で役立つポイントを静かに整理しています。
難しいことを増やすのではなく、コードの見通しが少し良くなるヒントを届けるのが役目です。

「この処理はどこに書くのがいいのか」
「Laravelではどう考えると整理できるのか」

そんな疑問に、小さなメモを残すような気持ちで記事を書いています。

コードを書いている途中で迷ったとき、
このサイトが少し立ち止まって整理できる場所になればうれしいです。

レン (Wren)をフォローする