dispatch_sync — 同期実行でジョブを即時処理するヘルパ

helper
  • カテゴリ: helper
  • 掲載バージョン: Laravel 12・PHP 8.4
  • 名前空間 / FQCN / コマンド: dispatch_sync()(グローバル関数)
  • 関連: dispatch / SomeJob::dispatchSync() / dispatch_now(非推奨) / php artisan queue:work
  • 変更履歴: Laravel 8.36 で追加。dispatch_now の後継として dispatchSync / dispatch_sync 系が推奨扱いに。(Pascal Baljet Blog)

要点(TL;DR)

  • 何に使うか:ジョブを「キューに積まず」、その場で即時実行(同期処理)したいときに使う。(readouble.com)
  • 最低限の使い方dispatch_sync(new App\Jobs\SendEmails());
  • よくある罠
    • 非同期だと思って使うと、リクエストが重くなりタイムアウトしやすい
    • 例外がそのままコントローラまで伝播する(キューの失敗処理が効かない)
    • QUEUE_CONNECTION=sync と組み合わせて挙動が分かりづらくなる

概要

dispatch_sync は、Laravel のジョブを 即時実行 するためのグローバルヘルパです。通常の dispatch がバックグラウンド処理(queue+worker 前提)であるのに対し、dispatch_sync は「今のプロセス内で handle() を実行して欲しい」ときに使います。(readouble.com)

テストコードや一部のメンテナンスコマンド、ワーカーを立ち上げたくない小規模 CLI などで「手軽に同期実行したい」ケースに向きます。

構文 / シグネチャ

/**
 * 指定したジョブを sync キューで即時実行する
 */
function dispatch_sync(object $job): mixed;

引数

引数必須既定値説明
$jobobjectなし実行したいジョブ。通常は App\Jobs\* のインスタンス

戻り値

  • 通常はジョブの handle() の戻り値
  • 戻り値を使わないことも多いが、サービス層の結果を返す用途も可能

例外 / 副作用

  • ジョブ内でスローされた例外は そのまま 呼び出し元へ伝播(キューの「失敗キュー」「自動リトライ」は使われない)
  • バックエンドのキューには積まれず、現在プロセスの実行時間がその分だけ延びる(readouble.com)

使用例

最小例

メール送信を同期実行したいパターン。

<?php

use App\Jobs\SendWelcomeMail;
use App\Models\User;
use Illuminate\Http\Request;

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

    // このリクエスト中にメール送信まで完了させたい場合
    dispatch_sync(new SendWelcomeMail($user));

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

実務例:管理画面からの「即時処理」ボタン

管理者が手動でレポート再生成を行う CLI/管理画面などで、ワーカーを気にせず即時実行したいケース。

<?php

use App\Jobs\RebuildAnalyticsCache;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

Route::post('/admin/analytics/rebuild', function (Request $request) {
    abort_unless(Auth::user()?->isAdmin(), 403);

    // 非同期だと「終わったのか分からない」問題が出るので同期実行
    dispatch_sync(new RebuildAnalyticsCache(
        period: $request->input('period', '7days'),
    ));

    return back()->with('status', '解析キャッシュを再生成しました。');
});
  • 処理時間は伸びるが、「完了するまで待って、その結果を管理画面で確認したい」用途には分かりやすいです。

よくある落とし穴・注意

  • 「非同期」ではない
    • 名前が dispatch なので勘違いしやすいですが、dispatch_sync完全に同期処理 です。
    • 実行が終わるまで HTTP レスポンスは返りません。
  • 重い処理を HTTP リクエストで dispatch_sync しない
    • 画像変換・大規模バッチなどを dispatch_sync で回すと、タイムアウトや 502 の原因になりやすいです。
    • 時間のかかる処理は基本 dispatch + queue:work でワーカーへ任せるべきです。(laravel.com)
  • 例外ハンドリングの違い
    • キュー経由なら「失敗ジョブテーブル」「再試行」などの仕組みが使えますが、dispatch_sync では単なる関数呼び出しです。
    • 例外が上まで飛んでアプリ全体が 500 になることもあるので、必要ならコントローラ側で try/catch するか、ジョブ側で握り潰す設計にします。
  • QUEUE_CONNECTION=sync と混同しない
    • .envQUEUE_CONNECTION=sync にすると、通常の dispatch も同期実行になります。
    • そこにさらに dispatch_sync を混ぜると、「どれが本当にキューなのか」が分かりづらくなります。
    • テスト環境でのみ QUEUE_CONNECTION=sync にする、など役割を整理すると理解しやすくなります。(Qiita)

代替・関連APIとの比較

  • dispatch()
    • 基本は非同期キュー用。「ユーザー操作のレスポンスを早く返したい」「バックグラウンド処理向け」。
    • ワーカーが必須。失敗ジョブ、リトライ、遅延などの機能が使える。(laravel.com)
  • SomeJob::dispatchSync()
    • ジョブクラスの静的メソッド版。
    • ProcessPodcast::dispatchSync($podcast); のようにクラス側から呼びたいときに使う。(readouble.com)
  • dispatch_now()(非推奨)
    • 旧来の同期ディスパッチメソッド。Laravel 8 以降は dispatchSync / dispatch_sync へ移行。(Pascal Baljet Blog)
  • QUEUE_CONNECTION=sync
    • 環境側の設定で「すべてのジョブを同期にする」やり方。
    • テストやローカル開発には便利だが、「本番で一部だけ同期にしたい」場合は dispatch_sync のほうが明示的で安全。

テスト例(Pest)

dispatch_sync を使うとジョブの handle() が即時実行されることを検証する例。

<?php

use App\Jobs\IncrementCounter;
use App\Models\Counter;

it('runs job immediately with dispatch_sync', function () {
    $counter = Counter::create(['value' => 0]);

    dispatch_sync(new IncrementCounter($counter->id));

    $counter->refresh();

    expect($counter->value)->toBe(1);
});

このように、キューのフェイクを使わずに「副作用がその場で反映されること」を直接テストできます。

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

症状/エラー原因対処
リクエストが異常に重い・タイムアウトする重いジョブを dispatch_sync で実行している重い処理は dispatch に切り替え、キューワーカーで処理する
ジョブ失敗がログに残らない/失敗テーブルに記録されない同期実行なので「失敗ジョブ」の仕組みに乗っていない失敗を記録したいなら dispatch + キューワーカーを使用するか、try/catch 内で明示的にログ・通知する
テストでだけ挙動が違うテスト環境で QUEUE_CONNECTION=sync にしているうえに dispatch_sync も使っており、設計意図と違う動きになっているテストで「ジョブの存在だけチェックしたい」のか「処理まで実行したい」のかを整理し、dispatch_sync / dispatch / Queue::fake の使い分けを見直す

参考リンク

レン (Wren)

こんにちは。レンです。

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

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

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

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

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

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