数秒かかる処理はHTTPリクエストを開いたままにし、Webサーバーのリソースを消費します。また、接続が切れると、ユーザーに不確かな体験をもたらす可能性があります。PHPのバックグラウンド処理を使えば、処理を受け付けたうえで、そのリクエストのライフサイクル外で実行できます。ただし、役立つ仕組みにするには、キューを追加するだけでは不十分です。ユーザーに何を伝えるか、状態をどう確認するか、中断時に何が起きるかを定義する必要があります。
バックグラウンドで実行すべき処理を見極める

処理時間だけに基づくルールを適用するのではなく、その処理がもたらす影響を評価しましょう。所要時間にばらつきがある、外部システムの応答待ちが発生する、多数の項目を処理する、といったタスクは候補になります。長大なレポートの生成、ファイルのインポート、ドキュメントの変換、APIとのデータ同期などが例です。
一方、保存前に必須データを検証するように、ユーザーが次へ進むために即時の判断を必要とする場合は、その処理をリクエスト内に残し、後続の作業だけを切り離すほうが適切なことがあります。また、ビジネス要件により同期応答が必要な低速タスクもあります。アーキテクチャはフローのニーズに応えるべきであり、すべての処理を非同期にする必要はありません。
設計を変更する前に、処理にかかる時間、その時間を消費する部分、失敗した場合に何が起きるかを把握してください。キューを追加しても、非効率なクエリ、不適切な制限、不安定な外部依存関係が自動的に解消されるわけではありません。そうした問題がバックグラウンドワーカーに移る可能性があります。
結果を作り上げず、タスクの受け付けを伝える
後続の実行に向けて処理を受け付けた場合、アプリケーションの応答では受け付け済みと完了済みを明確に区別します。タスクIDと、処理が保留中であることを示す情報を返せます。まだ存在しない結果を、完了したかのように提示してはいけません。
所要時間の見積もりは、算出に十分な情報があり、その不確実性を伝えられる場合に限り適切です。多くのシステムでは、完了時刻を約束するより、「キュー待ち」や「処理中」といった状態を表示するほうが誠実です。タスクがすぐ完了する可能性がある場合も、元のリクエストをブロックせずに、インターフェースから状態を確認し、結果が利用可能になった時点で表示できます。
キューへの送信に失敗した場合の動作も定義してください。処理を確実に記録できないなら、アプリケーションは受け付けを確認してはいけません。具体的な仕組みはアーキテクチャによりますが、応答と永続化された状態には一貫性が必要です。
状態と有効な遷移を定義する
小さく明示的なライフサイクルは、ユーザー体験と運用の両方を容易にします。基本として、pendiente、en_proceso、cancelacion_solicitada、completada、fallida、canceladaを検討できます。名称は異なってもかまいませんが、状態遷移は自由な組み合わせではなく、有効かつ検証可能でなければなりません。
- 通常の遷移:
pendiente → en_proceso。さらにen_procesoからcompletadaまたはfallidaへ遷移します。 - 開始前のキャンセル: ワーカーがまだ処理を開始していないと確認できた場合、
pendiente → cancelada。 - 実行中のキャンセル:
en_proceso → cancelacion_solicitada。この状態から、安全に停止できればcanceladaへ遷移します。要求に対応する前に処理が終わった場合はcompletada、エラーが発生した場合はfallidaへ遷移することもあります。 - 終端状態:
completada、fallida、canceladaからアクティブな状態へ戻すべきではありません。タスクの再実行を許可する場合は、新しい実行を作成するか、別のライフサイクルを明示的に定義してください。
システムは許可されていない遷移を防ぎ、各変更の発生時刻を記録する必要があります。ワーカーが中断され、タスクがen_procesoのまま残っても、自動的に完了扱いにしてはいけません。安全に再開できる場合は復旧ポリシーによってpendienteに戻し、そうでなければレビュー用にfallidaとします。判断は、効果を重複させずに処理を再開できるかどうかによります。再試行と冪等性の調整には別途判断が必要であり、ユーザーに見せる状態モデルと混同してはいけません。
進捗、結果、エラーを伝える
進捗は測定可能なマイルストーンに基づかせます。実際の割合を算出できない場合は、「データを検証中」「レポートを生成中」といった段階を示すか、「処理中」の状態を維持するほうが適切です。説明のないまま動かなくなったり、後退したりする割合表示は信頼を損ないます。
完了時には、処理した項目の概要や生成したリソースへの参照など、ビジネス上の結果を提示します。ただし、権限と利用可能性を考慮してください。タスク状態に結果全体を保存する必要はありません。アプリケーションのドメインが管理するデータへの参照を保存できます。
失敗時は、ファイルの修正や、該当する場合の再試行など、次の対応を判断できるメッセージを表示します。診断に必要な技術的エラー情報は別に記録し、アクセスを制限してください。トレース、認証情報、内部パス、機密データをインターフェースや公開APIに出してはいけません。
制限のあるリクエストとしてキャンセルを扱う
タスクをキャンセルしても、必ずしも即座に停止できるとは限りません。ワーカーが外部呼び出しを実行中、データを書き込み中、または安全に中断できない段階にいる可能性があります。そのため、インターフェースではcancelacion_solicitadaとcanceladaを区別します。前者は要求を受け付けたこと、後者はシステムが停止を確認したことを示します。
実装では、安全な箇所でキャンセルシグナルを確認し、それ以降のステップを開始しないようにできます。外部システムで効果がすでに確定している場合、それが取り消されたと主張してはいけません。ユーザーが期待できる結果を説明し、監査上必要であれば、誰がキャンセルを要求したかを記録してください。
タスクの記録とビジネス上の結果を分離する
タスクの記録は、実行の調整や状態確認に使います。ID、状態、日時、依頼者、診断情報への参照などを含められます。レポートやインポートされたレコードなどのビジネス上の結果は、その結果を表すデータモデルに属します。
分離すれば、一時的な情報を持つタスクがビジネスデータの唯一の情報源になるのを防げます。また、状態をどれくらい保持するか、ファイルをいつ削除するか、運用上または規制上の義務によりどの情報を維持する必要があるかといった保持期間も定義できます。古い状態を、整理方針なしに蓄積させてはいけません。
状態確認を保護し、リソース消費を制限する
タスクの状態確認にも、ほかのリソースと同じように認可が必要です。IDはアクセス制御の代わりにはなりません。要求元のユーザーやシステムが、そのタスクと結果を閲覧できることを確認してください。また、過剰なポーリングを防ぐため、確認頻度と量を制限し、ユースケースで常時更新が不要なら通知も検討します。
実行には、処理の種類に応じた同時実行数とリソースの上限が必要です。ワーカーが多すぎるとデータベース、外部サービス、ストレージを圧迫し、少なすぎるとタスクが滞留して結果が遅れます。エラーだけでなく、保留中の件数、タスクの経過時間、処理時間も監視してください。これらの指標は、依存先の遅延と処理能力の問題を見分けるのに役立ちます。
デプロイ前にライフサイクル全体をテストする
受け入れテストでは、ワーカーが関数を呼び出すことだけでなく、ユーザーに見える動作と永続化も検証します。少なくとも次のシナリオを確認してください。
- リクエストでタスクが作成され、すでに完了したとは主張せずに参照が返される。
- 完了したタスクに最終状態が表示され、適切な権限で結果にアクセスできる。
- 失敗したタスクでは安全なメッセージが表示され、権限のあるチームが診断情報にアクセスできる。
- 放置または中断されたタスクが「処理中」のまま無期限に残らず、運用上、検出して対処する手段がある。
- キャンセル要求が安全な段階に従い、すでに生じた効果を取り消すと約束しない。
既存システムでは、対象を限定した処理から変更を導入し、キューが遅延または利用不能な場合の体験も検証してください。そのようなケースに対し、アプリケーションは明確な対応を用意する必要があります。処理を受け付けられなかったと伝える、安全な代替手段を提示する、またはユーザーが再試行できるようにする、といった方法です。選択は処理の影響と、ビジネスとして保証できる内容によります。
既存システムにキューを導入する際のチェックリスト

バックグラウンド処理を有効にする前に、アプリケーションと運用を担当するチームと次の項目を確認してください。
- 範囲: 対象とする処理が具体的に選ばれており、同期のまま残す部分とバックグラウンドで実行する部分が定義されている。
- 永続化: タスクの受け付けと状態が一貫性をもって保存され、中断、復旧、状態変更に関する方針がある。
- ユーザーとの取り決め: 初回応答で受け付けと完了を区別し、進捗、結果、エラーの確認方法をインターフェースで説明している。
- 権限とデータ: タスクや結果の確認に認可が必要であり、保存データを最小限にし、診断情報へのアクセスを制限している。
- リソース: 処理と依存先に適した同時実行数、実行時間、メモリ、確認頻度の上限が設定されている。
- 可観測性: 秘密情報をログに含めずに、滞留、処理中のまま古くなったタスク、失敗、異常な所要時間を検出できる。
- 保持期間: 状態、結果、ファイル、診断データをどれだけ保持するか、また管理された方法でどう削除するかが決まっている。
- テストと運用: 完了、失敗、キャンセル、中断の各経路がテストされ、キューが処理を受け付けない場合や遅延する場合の対応をチームが把握している。
コードのデプロイは、すべてのフローをただちに有効化することと同じではありません。新しい実行経路を段階的に導入し、指標を確認してから対象を広げられます。キューやワーカーが利用できない場合に備え、適切な運用上の代替手段を用意してください。システムが記録できなかった処理を、受け付け済みとして確認してはいけません。



