laravel-queues について
Laravel 13 のキュー開発と運用を支援するスキルです。設定、ジョブ設計、再試行、スケーリング、テストを扱う20のルールで、本番負荷で問題になりやすい実装を監査します。
主な機能
- 016 分野、20 のキュールール
- 02キュー設定とジョブの確認
- 03再試行と失敗処理の点検
- 04ワーカーの拡張と再起動
- 05バッチ、チェーン、テストの指針
活用シーン
- 01バックグラウンドジョブの設計・レビュー
- 02停止または失敗を繰り返すジョブの調査
- 03Redis キューワーカーの設定
- 04キューテストや Horizon 導入の検討
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ asyrafhussin/ agent-skills --skill laravel-queuesインストール後、Claude Code で/laravel-queuesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
AGENTS.mdmetadata.jsonREADME.mdrules/_sections.md_template.mdbus-batch-failure-handling.mdbus-batch-vs-chain.mdbus-chunking-large-sets.mdconfig-after-commit.mdconfig-driver-choice.mdconfig-failed-storage.mddesign-constructor-vs-handle.mddesign-idempotency.mddesign-pass-ids-not-models.mddesign-shouldqueue.mdops-horizon-when.mdops-queue-fake.mdops-schedule-queued-jobs.mdretry-fail-on-timeout.mdretry-failed-method.mdretry-transient-vs-permanent.mdretry-tries-and-backoff.mdscaling-multi-queue-priority.mdscaling-supervisor-config.mdscaling-worker-recycling.md詳細
Laravel のキューとジョブ
Laravel 13(MySQL + Redis)向けの、本番環境に適したキューパターンです。ドライバーの選択、ジョブの設計、リトライと失敗への対応、ワーカーのスケーリング、バッチ処理とチェーン処理、テストを扱う6つのカテゴリーに、20のルールを収録しています。コードレビューを通過しても負荷がかかると問題になる失敗パターンを対象としています。たとえば、リトライ時に気付かないまま再ディスパッチされる、シリアライズ後にモデルが古い状態になる、決済ジョブに冪等性がない、ワーカーでメモリリークが発生する、「ShouldQueue を付け忘れて、本番環境でリクエストに12秒かかる」といった問題です。
メタデータ
- バージョン: 1.0.0
- 対象範囲: PHP / Laravel 13 + MySQL + Redis(キュー)、Horizon は任意
- ルール数: 6つのカテゴリーに20のルール
- ライセンス: MIT
使い方
ユーザーから「このバックグラウンドジョブを設計して」「キュー設定を監査して」「このジョブが実行されない理由は?」「キューに関する質問」などを受けた場合は、このスキルのルールをチェックリストとして、該当ファイル(ジョブクラス、config/queue.php、config/horizon.php、Supervisor の設定、ディスパッチ呼び出し箇所)を確認してください。
監査モードでは、ルールごとに次の判定を出力してください。
- PASS — パターンが正しく適用されています
- FAIL — アンチパターンが存在します(ファイル名と行番号、および修正の推奨事項を記載)
- N/A — このコードベースには該当しません
最後に、優先度の高い修正項目のリストを示してください(決済ジョブの冪等性、ShouldQueue の付け忘れ、Supervisor の stopwaitsecs が短すぎること。本番環境で問題になりやすいのは、これらが最も一般的です)。
適用する場面
次の場合は、このスキルを参照してください。
- 新しいバックグラウンドジョブを作成するとき(
php artisan make:job) - ジョブクラスを追加または変更する PR をレビューするとき
- 新しいサーバーでキューワーカーを設定するとき(Forge / Vapor / ベアサーバー)
config/queue.phpまたはconfig/horizon.phpを設定するとき- 停止した、ループする、または繰り返し失敗するジョブをデバッグするとき
dispatch()、dispatchSync()、dispatchAfterResponse()、Bus::batch()、Bus::chain()のいずれを使うか選ぶとき- キューテスト(
Queue::fake()、Bus::fake())を追加するとき - Horizon を採用するかどうか判断するとき
ステップ1:キューの設定を確認する
次を調べます。
| ファイル | 確認する内容 |
|---|---|
config/queue.php | デフォルトの接続(QUEUE_CONNECTION 環境変数)、失敗ジョブの保存先、after_commit の設定 |
config/horizon.php(存在する場合) | Horizon の環境、バランス戦略、ワーカー数、タイムアウト |
app/Jobs/*.php | ジョブクラス、ShouldQueue の使用状況、tries/backoff、failed() メソッド |
app/Console/Kernel.php または routes/console.php | スケジュールされたジョブ(Schedule::job(...)、withoutOverlapping) |
database/migrations/*_create_failed_jobs_table.php | 失敗ジョブ保存用のマイグレーション、または設定における DynamoDB ドライバー |
supervisor*.conf / /etc/supervisor/conf.d/ | ワーカープロセスの管理、numprocs、--max-time、stopwaitsecs |
一般的な構成:
| スタック | キュードライバー | 失敗ジョブ用ドライバー | ワーカー管理 |
|---|---|---|---|
| 小規模な Laravel + MySQL | database | database | Supervisor(または systemd) |
| 本番環境の Laravel + Redis | redis | database(またはサーバーレス環境では dynamodb) | Supervisor + Horizon |
| Laravel Vapor | sqs | dynamodb | Vapor による管理 |
優先度別のルールカテゴリー
| 優先度 | カテゴリー | 影響度 | プレフィックス |
|---|---|---|---|
| 1 | ドライバーと設定 | CRITICAL | config- |
| 2 | ジョブ設計 | CRITICAL | design- |
| 3 | リトライと失敗 | HIGH | retry- |
| 4 | スケーリングとワーカー | HIGH | scaling- |
| 5 | バッチ処理とチェーン処理 | HIGH | bus- |
| 6 | テストと運用 | MEDIUM | ops- |
クイックリファレンス
1. ドライバーと設定(CRITICAL)
config-driver-choice— 小規模なアプリにはdatabase、本番環境での大規模運用にはredis、Laravel Vapor にはsqsを使用しますconfig-after-commit— 未コミットの DB 行を参照するジョブがディスパッチされないよう、after_commit: trueに設定しますconfig-failed-storage—failed_jobsテーブル(または Vapor では DynamoDB)が必要です。保持期間とクリーンアップを設定してください
2. ジョブの設計(最重要)
design-shouldqueue— すべての非同期ジョブでShouldQueueを実装する必要があります(本番環境で最も多いバグ:実装を忘れるとジョブが同期的に実行されます)design-pass-ids-not-models— コンストラクターには ID を渡し、handle()で再取得します。古くなったモデルや肥大化したシリアライズ済みペイロードを避けられますdesign-idempotency— 決済、外部 API、「リソースの作成」を行うジョブは、2 回実行されても安全である必要があります(ShouldBeUnique、冪等性キー、一意制約のある DB)design-constructor-vs-handle— コンストラクターはディスパッチ時(同期)に実行され、handle()はワーカー上で実行されます。コンストラクター内で DB への書き込みや HTTP 呼び出しを行わないでください。
3. 再試行と失敗(重要)
retry-tries-and-backoff— 両方を設定します。指数的な遅延には#[Backoff([1, 5, 30])]を使用します。デフォルトの 3 回では、一時的な障害に対して通常は不十分ですretry-failed-method— 恒久的な失敗への対応(通知、返金、失敗としてマーク)には、failed(Throwable $e)を実装しますretry-transient-vs-permanent— 一時的なエラー(レート制限、ネットワーク障害)にはrelease($delay)を使用し、恒久的なエラーには例外をスローしますretry-fail-on-timeout— ハングしたジョブですべての試行が無駄になるのを避けるには、#[FailOnTimeout]を使用します
4. スケーリングとワーカー(重要)
scaling-supervisor-config— Supervisor(または systemd)でワーカーを管理します。stopwaitsecs > timeoutとし、ワーカーを再起動するには--max-time=3600を指定しますscaling-multi-queue-priority— SLA が重要なジョブには high/default/low のキューレーンを使用します。--queue=high,default,lowscaling-worker-recycling— 長時間稼働するワーカーのメモリーリークを抑えるには、--max-jobsと--max-timeを使用します
5. バッチ処理とチェーン処理(重要)
bus-batch-vs-chain— 並列処理と進捗追跡にはBus::batch、厳密な順次処理にはBus::chainを使用しますbus-batch-failure-handling— 障害許容型のバッチにはallowFailures()を使用し、then/catch/finallyコールバックを活用しますbus-chunking-large-sets— 1000 件以上の項目を処理する場合は、項目ごとに 1 つのジョブを作成するのではなく、Bus::batch(...)でチャンクに分割します
6. テストと運用(中程度)
ops-queue-fake— テストではQueue::fake()/Bus::fake()を使用します。assertDispatched、assertPushed、assertChained、assertBatchedを利用できますops-schedule-queued-jobs—Schedule::job(new X)->everyMinute()はジョブをキューに追加します。安全のため、withoutOverlapping()と組み合わせますops-horizon-when— 複数のスーパーバイザーを使用する Redis 環境では Horizon を導入します。databaseキューや単一ワーカーの構成には適していません
必須パターン
最小限のジョブクラス(Laravel 13)
<?php
namespace App\Jobs;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\Attributes\Backoff;
use Illuminate\Queue\Attributes\FailOnTimeout;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Throwable;
#[Backoff([1, 5, 30])]
#[FailOnTimeout]
class ChargeOrder implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $tries = 5;
public int $timeout = 30;
public function __construct(public readonly int $orderId) {}
public function handle(StripeGateway $stripe): void
{
$order = Order::findOrFail($this->orderId); // refetch — don't trust serialised state
if ($order->status === 'paid') return; // idempotency guard
$charge = $stripe->charge($order);
$order->markPaid($charge->id);
}
public function failed(Throwable $e): void
{
Order::find($this->orderId)?->markPaymentFailed($e->getMessage());
}
}
ディスパッチ
ChargeOrder::dispatch($order->id); // default queue
ChargeOrder::dispatch($order->id)->onQueue('high'); // priority lane
ChargeOrder::dispatch($order->id)->delay(now()->addMinutes(5));
ChargeOrder::dispatchAfterResponse($order->id); // run after HTTP response sent
Supervisor の設定(推奨)
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/app/artisan queue:work redis --queue=high,default,low --sleep=3 --tries=3 --max-time=3600 --backoff=3
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=forge
numprocs=8
redirect_stderr=true
stdout_logfile=/var/www/app/storage/logs/worker.log
stopwaitsecs=3600
重要: stopwaitsecs は最も時間のかかるジョブのタイムアウトより大きくする必要があります。そうしないと、デプロイ時に Supervisor がジョブの実行途中でプロセスを終了します。
参考資料
コンパイル済みドキュメント全文
すべてのルールを詳しく記載した完全なガイド:AGENTS.md