- Laravel は、複数のドライバー (データベース、Redis、SQS など) と接続と論理キューの分離を備えた統合キュー API を提供します。
- ジョブを使用すると、モデル、ミドルウェア、1 回限りのジョブ、暗号化、バッチ、文字列のシリアル化をサポートし、負荷の高いタスクをバックグラウンドに移動できます。
- ワーカーは、queue:work、Supervisor、および再試行、タイムアウト、優先度を制御する queue:pause/queue:continue などのコマンドを使用して管理されます。
- 失敗、監視、テスト (failed_jobs、queue:retry、queue:monitor、Queue::fake) のための完全なエコシステムがあり、運用環境でキューの信頼性を高めます。
Laravelでキューを扱うことは、ある程度本格的なプロジェクトではほぼ必須です。メールの送信、CSVファイルの処理、PDFの生成、画像のリサイズ、外部APIの呼び出しなど、これらすべてをメインのHTTPリクエストで行うと、ウェブサイトの動作が遅くなり、500エラーが発生し、ユーザーは最終的に真っ白な画面をただ見つめるだけになってしまいます。
朗報です。Laravelは強力かつ柔軟なキューイングインフラストラクチャを提供しており、重い処理をバックグラウンドプロセスに委任したり、優先度で管理したり、バッチにグループ化したり、監視したり、失敗した場合に再試行したり、メンテナンスのためにワーカーを一時的に停止したりすることができます。本番環境での一時停止、再開、動作制御の方法を含め、この機能を最大限に活用する方法を詳しく見ていきましょう。
基本概念: 接続、キュー、ドライバー
Laravelでは、何かを一時停止する前に、次の違いを理解する必要があります。 キュー接続とキュー自体。 で config/queue.php 配列があります connections 各バックエンドを定義する場所: データベース、Redis、Beanstalkd、SQS、同期、Null、フェイルオーバー、RatbigMQ (追加する場合)など
各接続には複数の 論理キュー (名前など default, emails, high, low, imports属性 queue 各接続は、他に指定がない場合にジョブが送られるデフォルトのキューを示します。 onQueue()この方法では次のようなことが可能になります:
- クイックキュー 電子メールや短い取引の場合。
- もう一つの低優先度 ビデオや大規模なレポートの処理などの長時間のタスクに適しています。
- タスクタイプ別に分割されたキュー:
imports,notificaciones,reportes, etc.
ワーカーを起動すると php artisan queue:workデフォルトでは、次のように指定されたキューをリッスンします。 デフォルト 選択した接続で優先順位を付ける場合は、複数のキューをカンマで区切って渡すことができます。
php artisan queue:work redis --queue=high,default,low
こうすることで、ワーカーはまず優先度の高い処理、次にデフォルトの処理、そして最後に優先度の低い処理を行います。これは、システムに負荷がかかっているときに、30分かかるレポート処理によって優先度の高いメールがブロックされるのを防ぐ上で非常に重要です。
キュードライバーと前提条件
Laravelは複数のキュードライバーに対応した統一APIを提供していますが、それぞれに固有の機能と依存関係があります。ワーカーの一時停止について議論する前に、適切なドライバーを選択することが非常に重要です。
ドライバーデータベース
ドライバ データベース ジョブはSQLテーブル(通常は jobsセットアップが簡単で、Redis や SQS を扱いたくない小規模なプロジェクトや開発環境に最適です。
基本的な手順:
- 移行を生成します:
php artisan queue:table(または新しいバージョンでは、create_jobs_tableポー・デフェト)。 - 移行を実行します。
php artisan migrate. - 設定する QUEUE_CONNECTION=データベース
.envそして確認するconfig/queue.phpその'default' => env('QUEUE_CONNECTION','database').
便利で堅牢ではあるものの、キューが多くトラフィックが多い場合は、すべてが同じリレーショナルデータベースを経由するため、ボトルネックになる可能性がある。
ドライバーRedis
Redisドライバは、本番環境における標準的な主力ドライバです。高速で、高度な機能(ロック、レート制限、アトミックロック、Horizonなど)をサポートし、非常に優れたスケーラビリティを備えています。
重要なポイント:
- Redis接続を設定する必要があります
config/database.php. - オプション
serializerycompressionRedisから 彼らは互換性がありません キュー ドライバーを使用します。 - 使用する場合 Redisクラスターキューの名前にはハッシュタグが必要です。例:
{default}そのキュー内のすべてのキーが同じスロットに収まるようにします。 - 選択
block_forこれにより、ワーカーは継続的にポーリングする代わりに、数秒間ジョブを待機しながらブロックできるようになります。 CPUを節約 Redis サーバーへのクエリを削減します。
例えば:
'redis' => ,
もしあなたが ブロック_for = 0ワーカーはジョブが利用可能になるまで無期限にブロックされたままになります。これは、次のような信号に素早く反応させたい場合に留意すべき点です。 SIGTERM または一時停止コマンド。
その他のドライバー: SQS、Beanstalkd、null、フェイルオーバー…
LaravelはデータベースやRedisに加えて、以下のシステムもサポートしています。
- アマゾンSQSAWS上のマネージドキュー(サポート対象: FIFOメッセージグループ、重複排除、および高度な可視性設定。SDK が必要です。
aws/aws-sdk-php. - 豆まきパッケージを使用すると非常に迅速かつ簡単です
pda/pheanstalk. - sync: タスクを実行する すぐに 同じプロセスで。開発やテストでは便利ですが、本番環境では実質的にキューを全く使用していないのと同じです。
- ヌル: ジョブが「ディスパッチ」されるとすぐに破棄します。キューイングシステムを完全に無効にするために使用します。
- フェイルオーバーこれにより、複数の接続を設定でき、主要な接続が失敗した場合、Laravelはリスト内の次の接続にジョブをプッシュしようとします。 高可用性 それは重要です。
ワーカーの一時停止と再開のレベルでは、ロジックはドライバーに関係なく実質的に同じです。なぜなら、それはキューのバックエンドではなく、 ArtisanコマンドとWorkerクラスから管理されるからです。
ジョブの作成とモデルのシリアル化
Un Job Laravelでは、キューで実行されるタスクをカプセル化するクラスです。通常はArtisanで生成され、 app/Jobs.
作成するには:
php artisan make:job ProcessPodcast
生成されたクラス 実装 ShouldQueue そして通常は特性を使用する Dispatchable, InteractsWithQueue, Queueable y SerializesModels心は方法にある handle()これは、仕事が来たときに労働者が行うことです。
特に強力な機能の一つは、Eloquentモデルの自動シリアライズです。Jobコンストラクタでモデルを受け入れる場合、Laravelはオブジェクト全体ではなく、識別子のみをキューに追加します。ジョブが処理される際、データベースからリレーションシップをロードしたモデルが再構築されます。
典型的な例(逐語的な繰り返しを避けるため、疑似コードで記載しています):
- ビルダーは受け取る ポッドキャスト $podcast.
- その特性
SerializesModelsID を保存する役割を担います。 - En
handle(AudioProcessor $processor)大変な作業(たとえば、オーディオの処理)は自分で行います。
モデル内の関係をシリアル化したくない場合は(ペイロードが巨大にならないように)、次のようにします。 $model->withoutRelations() またはPHP 8では属性 # 建築業者が宣伝している物件について。
ハンドルメソッドにおける依存性注入
もうXNUMXつの利点は、次のことができることです。 ハンドルメソッドにサービスを直接注入する Laravelはジョブ内でサービスコンテナも使用するため、コントローラーのように動作します。例えば、 AudioProcessorHTTP クライアント、リポジトリなどがあり、フレームワークがそれらの解決を担当します。
いわゆる「 handle使用できます Container::bindMethod() サービスプロバイダーでインジェクションロジックを自分で定義することもできますが、ほとんどの場合、それほど複雑にする必要はありません。
ジョブミドルウェア
ルートにミドルウェアがあるように、ジョブにも 特定のミドルウェア ジョブの前後に実行される。これにより、メソッド内の繰り返しコードが大幅に削減される。 handle() 特に以下の場合に役立ちます:
- レート制限 Redis を使用。
- 避けます 重なる 同じリソースに触れる作品。
- 通常の例外 不安定な API の場合。
- 特定の条件下でジョブをスキップする(
Skipミドルウェア)。
ミドルウェアは通常、 app/Jobs/Middleware メソッドから返される middleware() ヨブ記より。概念的な例:
public function middleware(): array { return ;
特殊なタイプのジョブ: ユニーク、暗号化、ロック
Laravelでは特定のジョブを 独特の 2つの同一のインスタンスが同時にキューに入れられないようにする。これは、インターフェースを実装することで実現される。 ShouldBeUnique o ShouldBeUniqueUntilProcessingキーの定義をサポート uniqueId() そして時間 uniqueFor.
これは次のような場合に最適です:
- 製品の検索インデックスを再計算します。 製品ごとに1回のみ 終わるまで。
- 同じリソースに対する同時要求を許可しない外部サービスとの同期。
その下には、Laravelが アトミックロック キャッシュの種類(Redis、memcached、データベースなど)。また、そのロックのキャッシュドライバを選択することもできます。 uniqueVia().
さらにインターフェースがあります ShouldBeEncrypted完了したジョブが 列に入る前にコードを入力してください機密データを渡すときに、そのデータを Redis、SQS、またはデータベースを介してプレーンテキストで送信したくない場合に非常に便利です。
さまざまなモードでジョブをディスパッチ、遅延、実行する
ジョブを定義したら、次のように起動します。 Job::dispatch() コントローラー、イベントリスナー、Artisanコマンド、あるいはクロージャーから渡されるパラメータは dispatch 彼らはジョブの建築家のところへ直接行きます。
興味深いバリエーション:
dispatchIf()ydispatchUnless()出荷品を単一ラインで調整します。delay()特定の日付/時刻までジョブを処理できないようにします。dispatchAfterResponse()oafterResponse()endispatch()クロージャは、HTTP 応答が送信されるまで実行を延期しますが、同じ PHP プロセス内です。dispatchSync()ジョブを同期的に(キューを通過せずに)実行しますが、同じクラスを再利用します。- 特別な接続例
deferredobackground応答後に同じプロセスまたは新しい PHP プロセスで実行します。
最後に、連鎖メソッドで接続とキューを指定できます。 onConnection() y onQueue()ディスパッチ時またはジョブ ビルダー内で実行します。
細かい制御: 再試行、バックオフ、タイムアウト、エラー処理
Laravelでキューを扱う上で重要なのは、ジョブを何回再試行するか、再試行の間隔をどれくらい空けるか、そしていつ失敗とみなすかを決定することです。
Opcionesの責任者:
--triesenqueue:workそのワーカーのすべてのジョブの最大試行回数を設定する(ジョブが独自に定義しない限り)$triesotries()).$triesまたは方法tries()ジョブごとの制御のためのジョブクラス。retryUntil()「この時までは好きなだけ挑戦して、その後は失敗だ」と言うのです。もしそれがtries、 指示retryUntil.$maxExceptions問題が繰り返し処理されない例外によって発生している場合は、切断します。$timeouto--timeoutワーカーが子プロセスを強制終了するまでにジョブを実行できる秒数を示します。$failOnTimeoutタイムアウトの場合にジョブを失敗としてマークします。$backoff方法backoff()再試行間の待機時間を指数値でも定義します。
ジョブがキャッチされていない例外をスローした場合、Laravel は... 尾部に戻って放出される 設定された試行回数に達するまで試行を続けます。手動で制御することもできます。 release($segundos) o fail($exception) ジョブを意図的に失敗としてマークしたい場合。
失敗したジョブ、failed_jobs テーブル、プルーニング
ヨブが努力を尽くすと、彼は 失敗した仕事 そしてLaravelはそれをテーブルに挿入します failed_jobs (または、そのように設定した場合は DynamoDB に保存されます)。このテーブルには、UUID、接続、キュー、ジョブのペイロード、およびスローされた例外が格納されます。
便利なコマンド:
php artisan queue:failed失敗したものをリストします。php artisan queue:retry <id|all>もう一度試してみましょう。php artisan queue:forget <id>1つ削除します。php artisan queue:flushすべてを削除します (新しいバージョンでは時間のオプションがあります)。php artisan queue:prune-failed --hours=48古いレコードを自動的に削除します。
ジョブではメソッドを定義できます failed(Throwable $exception) 追加のクリーンアップ: ユーザーに通知、部分的なアクションの取り消し、特別なログの書き込みなど。ジョブの新しいインスタンスが作成され、呼び出されることに注意してください。 failed()したがって、プロパティの変更に依存しないでください。 handle().
ジョブのバッチ処理: ジョブをバッチ化し、文字列で結合する
数百または数千の関連ジョブ(たとえば、巨大なCSVファイルをチャンクごとにインポートしたり、ファイルをバッチ処理したり、データをクリーンアップしたりなど)を実行する必要がある場合は、 Laravelのバッチ機能を使用することをお勧めします。
基本的な流れ:
- テーブルを作成する
job_batchesとともにphp artisan queue:batches-table && php artisan migrate. - バッチの一部となるジョブを特性でマークします
Batchable. - 使用
Bus::batch()コールバック付きのジョブセットを送信するthen,catchyfinally. - 各ジョブからバッチにアクセスするには
$this->batch()キャンセルされたかどうかを確認します。 - 進行中のバッチにジョブを追加する可能性
$this->batch()->add().
バッチ処理はチェーン処理と非常にうまく連携します。バッチ処理の中にチェーン処理を含めたり、バッチ処理をより大きなチェーン処理の要素として組み込んだりすることができます。これは、複数のチェーン処理を「並行」で実行し、すべてのチェーン処理が完了したときに何らかのアクションをトリガーしたい場合に特に便利です。
ワーカーの実行、優先順位、展開
キューの魔法は、 1人以上の労働者 コマンドの実行 queue:work (o queue:listen(ただし、後者は効率が悪くなります)。これらのプロセスは、それぞれのキューをリッスンする長時間実行されるデーモンです。
主なオプション queue:work:
- 接続:
php artisan queue:work redis,queue:work database, etc. - コーラ:
--queue=high,default,low優先順位をつける。 - -11: 単一のジョブを処理して終了します。
- –max-jobs: X 個のジョブを処理して終了します (定期的にワーカーを再起動してメモリを解放するため)。
- –最大時間: N 秒間処理して終了します。
- -寝る: 利用可能なジョブがない場合の待機秒数。
- –空になったら停止: キューを空にして、完全に閉じます (Docker 環境または 1 回限りのジョブに最適です)。
- -タイムアウト: 前述したように、ジョブあたりのタイムアウトの秒数。
- -力: アプリがメンテナンス モードの場合でもジョブを処理します。
これらのプロセスは長時間実行されるため、本番環境では、 Supervisor(Linuxの場合)のようなプロセスモニターを使用して、X個のワーカーを起動し、クラッシュした場合は再起動し、ログを管理します。Laravelの典型的なSupervisor設定ブロックでは、以下のように定義します。
- command と
php artisan queue:work ...コンクリート。 - numprocs 同時に起動するワーカーの数を指定します。
- ログ パス、ユーザー、自動再起動など。
Laravel でキューを一時停止および再開する
メンテナンスにおいてしばしば重要となる点、つまりキューワーカーを突然停止させたり、ジョブを未完了のままにしたりすることなく一時停止させる方法について見ていきましょう。Laravelには、これを制御するためのいくつかのメカニズムが用意されており、中には新しいものもあれば、従来からあるものもあります。
一時停止: queue:pause および割り込み信号
最近のLaravelバージョンでは、ワーカーの実行を一時停止および再開するための特定のコマンドが追加されています。
php artisan queue:pause: システムに新しいジョブの受け入れを停止し、すでに進行中のジョブを完了するように指示します。php artisan queue:continue: 中断したところから新しいジョブの処理を再開します。
これらのコマンドは、 Laravelが内部的に使用するキャッシュメカニズムを介してワーカーにシグナルを送信することで機能します。そのため、実際のキャッシュキューが別のものであっても、適切に設定されたキャッシュドライバ(memcached、redis、データベース、ファイルなど)を用意しておくことが重要です。
重要:キューまたはワーカーを一時停止しても、既にキューに登録されているジョブがキャンセルまたは削除されるわけではありません。一時停止中は、キューからさらにジョブが削除されるのを防ぐだけです。
混乱とパフォーマンスへの影響に関する調査
ワーカーがジョブを完了するたびに、Laravel はキャッシュをチェックして再起動、一時停止、または続行シグナルを検出します。これはごくわずかなコストですが、存在します。パフォーマンスを非常に重視し、コマンドからワーカーを一時停止または再起動する必要がないことがわかっている場合は、次の呼び出しでこのポーリングを無効にできます。
Queue::withoutInterruptionPolling();
あるいは静的プロパティを調整して Illuminate\Queue\Worker 特定のタッチを無効にするには($再起動可能, $一時停止可能しかし、これをしてから使用しようとすると queue:pause o queue:restart労働者たち 彼らは気づかないだろうこれは慎重に検討すべき設計上の決定です。
Supervisor または Docker を使用して手動で一時停止する
Laravel独自のコマンドに加えて、本番環境では、プロセスが間接的に「一時停止」されることがよくあります。
- スーパーバイザーでプログラムを停止する (
supervisorctl stop laravel-worker:*)、労働者を殺したり停止させたりします。 - 使用して –空になったら停止 デプロイメントでは、ワーカーがキュー内の処理を完了してからシャットダウンできるようにします。
- Dockerでは、コンテナに処理を実行させると、
--stop-when-emptyそして電源が切れます。
との違い queue:pause プロセスを完全に停止すると、ワーカーが再起動するまでジョブの処理が停止します。 内部の一時停止 プロセスをメモリに保持してコマンドを待つことができます continueこれは、迅速なロールバック展開や短いメンテナンス期間に役立ちます。
データベーストランザクションとafter_commit
よくある間違い:データベーストランザクション内でジョブをディスパッチすること。注意しないと、コミットが行われる前にワーカーがジョブを実行してしまい、期待していたモデルやデータがまだデータベースに存在しない可能性があります。
このダンスを回避するには、2 つの選択肢があります。
- 活性化します
'after_commit' => trueキュー接続設定で。したがって、トランザクション内でディスパッチされたジョブは、確認されるまで内部的に延期されます。 - ジョブごとのメソッドを使用する
afterCommit()obeforeCommit()ディスパッチ時に、特定のジョブでのみ動作を強制します。
トランザクションが取り消された場合、そのトランザクション中にディスパッチされたジョブはキューに入ることなく破棄されます。これは、一貫性を維持するために通常望まれる動作です。
監視、キューのクリーニング、テスト
キューが本格的に稼働し始めたら、ジョブを投入して放置するだけでは不十分です。すべての動作を監視し、テストする必要があります。
便利なツールとコマンド:
queue:clear特定のキュー (SQS、Redis、データベース) を空にします。queue:monitor特定のキュー内のジョブの数を監視し、イベントをトリガーするQueueBusyしきい値を超えた場合。- ジョブイベント として
Queue::before,Queue::after,Queue::loopingyQueue::failingカスタム ロジック (ログ、メトリック、ロールバックなど) をフックします。 - テストにおける偽造 使用して
Queue::fake()yBus::fake()ジョブ、文字列、またはバッチが実際に実行されずにディスパッチされたことを確認します。
テストでは、「このジョブはX回キューに入れられました」、「これらのジョブのチェーンがこの順序でディスパッチされました」、「特定のジョブはキューに入れられませんでした」といったことを記述することができ、複雑なフローにおいて高いセキュリティを提供します。
このエコシステム全体、つまりRedisやSQSのようなドライバー、よく設計されたジョブ、微調整のためのミドルウェア、バッチ、チェーン、再試行設定、スーパーバイザー管理のワーカー、そして次のようなコマンドによって、 queue:pause y queue:continue— Laravel を使用すると、一般的な電子メールの送信からフェイルオーバーを備えた分散キュー アーキテクチャまで、バックグラウンド処理をミリ単位まで制御できるため、ユーザーをブロックすることなく、負荷の高い作業が下で実行されている間も、アプリケーションが HTTP レイヤーで迅速に応答し続けることが可能になります。