- カテゴリ: 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;
引数
| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
$job | object | ○ | なし | 実行したいジョブ。通常は 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と混同しない.envでQUEUE_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)
- 旧来の同期ディスパッチメソッド。Laravel 8 以降は
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 の使い分けを見直す |

