Scheduler Agent Supervisor パターン

分散アクションのセットを 1 つの論理操作として調整し、操作全体が成功または失敗するようにします。 エラーを透過的に処理するか、完了した作業を元に戻します。 このアプローチでは、一時的な例外、長続きする障害、リモート サービスとリソース間で調整されたマルチステップ ワークフローを中断するプロセスエラーから復旧することで、分散システムに回復性を追加します。

コンテキストと問題

アプリケーションは、多くの場合、複数のステップにまたがるタスクを実行します。また、一部の手順では、アプリケーション ロジックのオーケストレーションの下でリモート サービスを呼び出したり、リモート リソースにアクセスしたりする場合があります。 ローカル プロセス以外の操作では、タスクがさまざまな障害モードに公開されます。 調整ロジックでは、操作全体の整合性を失うことなく、これらのエラー モードを処理する必要があります。

再試行パターンのようなアプローチを使用すると、一時的な障害など、単独で解決される単純な状況を処理できます。 障害がより永続的な場合、またはオーケストレーター自体が失敗した場合、システムは永続的なレコードから一貫した状態を復元し、操作全体の整合性を確保する必要があります。

ソリューション

Scheduler Agent Supervisor パターンは、3 つの論理アクターを介してマルチステップ分散タスクを調整します。 これらのアクターは、タスク全体の一部として実行されるステップを調整し、成功した実行と失敗した実行の両方を処理します。

Scheduler

Scheduler は、タスクを構成するステップを配置し、その実行を調整します。 Scheduler は、パイプラインまたはワークフローにステップを組み合わせ、正しい順序で実行する役割を担います。 各ステップが進行すると、Scheduler は、 まだ開始されていないステップ、 ステップの実行、 完了したステップなどの状態を記録します。 状態には、ステップの実行が許可される時間を制限する 完了 時間も含まれます。

ステップにリモート サービスまたはリソースが必要な場合、Scheduler は適切なエージェントを呼び出し、作業の詳細を渡します。 Scheduler は通常、非同期の要求/応答メッセージングを介してエージェントと通信します。多くの場合、キュー経由で実装されます。 代わりに、他の分散メッセージング テクノロジを使用できます。

Note

Scheduler は、プロセス マネージャー パターンのプロセス マネージャー ロールと同様の機能を実行 します。 Scheduler が制御するワークフロー エンジンは、通常、ワークフローを定義して実装し、Scheduler 自体からビジネス ワークフロー ロジックを切り離します。

エージェント

エージェントは、リモート サービスへの呼び出し、またはタスク ステップが参照するリモート リソースへのアクセスをカプセル化します。 各エージェントは、通常、単一のサービスまたはリソースへの呼び出しをラップし、Scheduler によって強制される完全な時間内に適切なエラー処理と再試行ロジックを実装します。 再試行ロジックが関係する場合、エージェントはすべての再試行で安定した識別子を渡します。 ダウンストリーム サービスでは、これを重複除去に使用できます。

ワークフロー内の異なるステップが異なるサービスまたはリソースを使用する場合、各ステップは異なるエージェントを参照できます。 そのマッピングは、パターンの実装の詳細です。 再試行戦略の設計に関するガイダンスについては、 一時的な障害処理のベスト プラクティスに関するページを参照してください。

スーパーバイザー

Supervisor は、Scheduler が実行するステップの状態を監視します。 Supervisor は、ワークロードで指定された頻度で定期的に実行され、Scheduler が記録したステップの状態を確認します。 Supervisor は、タイムアウトまたは失敗したステップを検出した場合、適切なエージェントがステップを回復するように調整するか、ステップの状態の変更を含む別の修復アクションをトリガーします。 Supervisor は、これらの復旧アクションのみを要求します。 Scheduler とエージェントはそれらを実装します。

インタラクション

Scheduler、Agent、Supervisor は論理コンポーネントであり、物理的な実装は使用するテクノロジによって異なります。 たとえば、1 つの Web サービスの一部として、または同じホストされているワーカー内のアクティビティとして、複数の論理エージェントを実装できます。

Scheduler は、タスクの進行状況とステップごとの状態を、 状態ストアと呼ばれる永続的なデータ ストアに保持します。 スーパーバイザはこの情報を使用して、ステップが失敗したかどうかを判断します。 以下の図は、スケジューラ、エージェント、スーパーバイザー、および状態ストアの関係を示しています。

共有永続状態ストアを介して対話する Scheduler、Agents、Supervisor を示す図。

左上にある Scheduler は、ステップを整理して実行します。 "Scheduler がエージェントにリモート リソースへのアクセスを要求します" というラベルの二重矢印線が右側のエージェントに移動し、"エージェントがリモート リソースまたはサービスにアクセスする" というラベルの二重矢印線がエージェントからリモート リソースを指します。 その下には、スケジューラから別のエージェントを指し、次にリモート サービスを指す二重矢印線があります。 "Scheduler はステップの状態を維持します" というラベルが付いたもう 1 つの二重矢印線は、状態ストアに下がります。 「Supervisor monitors step status」というラベルが付いた両矢印の線は、状態ストアとその右側にある Supervisor を接続しています。 「スーパーバイザーがステップの再実行を要求する」と書かれた矢印が、スーパーバイザーから上方向かつ左側にあるスケジューラーを指しています。

  • Scheduler は、タスクを構成するステップをワークフローとして整理して実行します。
  • ワークフローのステップは、リモート リソースにアクセスしたり、リモート サービスを呼び出したりするための要求をエージェントに送信できます。 通常、要求と応答は非同期的に送信されます。
  • エージェントがリモート リソースまたはサービスにアクセスします。 エージェントには、エラー処理と再試行ロジックを含める必要があります。
  • Scheduler は、開始および完了時に状態ストア内の各ステップの状態を維持します。
  • スーパーバイザーは、状態ストア内のステップのステータスを監視し、ステップのステータスの更新を要求することがあります。
  • Supervisor は、失敗したステップを再試行するようにスケジューラに要求します。

アプリケーションは、タスクを実行する準備が整うと Scheduler に要求を送信します。 Scheduler は、タスクとそのステップの初期状態 ( まだ開始されていないステップなど) を状態ストアに記録し、ワークフローが定義する操作の実行を開始します。 スケジューラは、各ステップを開始するたびに、そのステップの状態(たとえば step running など)を状態ストアに更新します。

ある手順がリモート サービスまたはリソースを参照した場合、Scheduler は適切な Agent にメッセージを送信します。 このメッセージには、エージェントがサービスを呼び出すか、リソースにアクセスするために必要な情報と、操作の完了時間と再試行許容量が含まれます。

エージェントは、その作業に適した再試行ロジックを実装できますが、エージェントが完了時間内にその作業を完了しなかった場合、Scheduler は操作が失敗し、応答の待機を停止すると見なします。 エージェントは期限を守る必要があり、時間の経過後に新しい副作用を開始してはなりませんが、既に進行中の作業は続行される可能性があります。

その操作を正常に完了した場合、Agent は Scheduler に応答を返します。 スケジューラは、状態をたとえばstep completedに更新し、次のステップを開始します。 タスク全体が完了するまで、このプロセスが続行されます。

Scheduler は遅延応答を無視する必要があり、エージェントは単独でワークフローの回復を試みてはなりません。 エージェント自体が失敗した場合、Scheduler も応答を受け取りません。 state store 内のステータスは、タイムアウトしたステップと失敗したステップを意図的に区別していません。

ステップがタイムアウトまたは失敗した場合でも、状態ストア レコードは ステップを実行中として表示しますが、完了期限が切れています。 Supervisor は、この状態のレコードをスキャンし、復旧を手配します。

また、スーパーバイザーは、同じステップが無期限に再試行されないようにする必要もあります。 Supervisorは、状態ストア内の状態情報とあわせて、各ステップの再試行回数を保持します。 カウントが定義済みのしきい値を超えた場合、その期間中に基になる障害が解消された場合に備えて、Scheduler にステップの再試行を求める前に、Supervisor を長時間待機するように設定できます。

可能な Supervisor 戦略の 1 つは、完了値を拡張し、タイムアウトしたステップを識別するメッセージを Scheduler に送信して、Scheduler が再試行できるようにすることです。 この設計では、同じ作業が複数回実行される可能性があるため、ステップロジックがべき等であることを要求します。

または、スーパーバイザーは、 補正トランザクションをトリガーしてタスク全体を元に戻すようにスケジューラに依頼できます。 この方法は、Scheduler とエージェントが、既に正常に完了した各ステップに対して補正操作を実装するのに十分な情報を提供することに依存します。 補正操作は通常、完了したステップの逆の順序で実行されるため、補正ログには順序付けと持続性が必要です。 補正操作自体が失敗すると、タスクは完了もクリーンに元に戻すこともできない状態になります。 状態ストアは、オペレーターが検索して調査できるように、この条件を表すことができる必要があります。

Note

Supervisor はスケジューラとエージェントを監視せず、失敗した場合は再起動します。 そのロールは、ホスティング インフラストラクチャに属します。 また、Supervisor は、スケジューラが実行しているビジネス 操作 (失敗した場合の補正方法など) を把握する必要はありません。 その知識は、Scheduler が実行するワークフロー ロジックに属します。 スーパーバイザーは、ステップが失敗したことを検出し、ステップを繰り返すか、失敗したステップを含むタスク全体を元に戻すために配置する必要があります。

このパターンの実際の実装では、Scheduler の複数のインスタンスが同時に実行され、それぞれがタスクのサブセットを処理します。 システムは、各エージェントの複数のインスタンス、または複数のスーパーバイザーを実行することもできます。 複数のスーパーバイザーがアクティブな場合、スーパーバイザは同じ失敗したステップまたはタスクを回復するために競合しないように調整する必要があります。 リーダー選定パターンは、スーパーバイザーを調整する 1 つの方法です。

このパターンの主な利点は、システムが一時的な障害と回復不能な障害の両方に対する回復性を維持し、自己復旧できるように構築できることです。 エージェントまたはスケジューラが失敗した場合は、新しいインスタンスを開始でき、Supervisor は影響を受けるタスクを再開するように手配できます。 Supervisor 自体が失敗した場合、前のインスタンスが停止した場所を別のインスタンスが引き継ぐ可能性があります。 Supervisor がスケジュールに従って実行されると、新しいインスタンスが次の間隔で自動的に開始されます。 耐障害性を高めるために、状態ストアを複製することもできます。

問題と考慮事項

このパターンを実装する方法を決定するときは、次の点を考慮してください。

  • 実装の複雑さ。 このパターンは実装が困難であり、システムで発生する可能性があるすべての障害モードを徹底的にテストする必要があります。 機能テストに加えて、フォールトインジェクションテストも計画してください。

  • 増幅を再試行します。 エージェント、オーケストレーション ランタイム、クライアント ライブラリ、メッセージング、および Supervisor レイヤーでの独立した再試行制限により、失敗した依存関係に対する呼び出しの数が乗算されます。 Scheduler を永続的なエンドツーエンドの再試行予算の所有者として指定し、他のレイヤーで再試行を構成または無効にして、合計最大値が予算を超えないようにします。

  • 受付管理。 このパターンでは、一度に実行できる作業量は制限されません。 Scheduler は受け入れる作業を失わないよう構築されているため、低速または失敗したダウンストリーム サービスでは、送信者に対して目に見えるバックプレッシャではなく、処理レコードの人口が増加します。 申請パスには、有界キュー、同時実行中タスクの上限、保留中のバックログがしきい値を超えた場合の新しい申請の拒否など、独自のアドミッション制御が必要です。 このバックプレッシャーにより、下流側での障害が気付かれないまま状態ストアのバックログが無制限に増大する事態を防ぎやすくなります。

  • 回復状態の持続性。 Scheduler の復旧と再試行のロジックは複雑であり、状態ストアに保持されている状態によって異なります。 また、永続ストアで補正トランザクションを実行するために必要な情報を記録する必要があり、補正トランザクション自体が失敗する可能性があります。 状態ストアと補正トランザクション ログをファースト クラスの永続資産として扱います。 これらの資産は、スケジューラ、エージェント、スーパーバイザよりも長期間存続する必要があり、また、それらに書き込みを行うワーカーとは独立して復元可能である必要があります。

    Important

    補正ログは、追跡する必要があるデータのデータ分類を継承する必要があります。ステップが顧客または支払いデータを受け入れる場合、補正トランザクション ログはその秘密度とそれに付随する保持ルールを継承します。

  • 二重書き込みの問題。 通常、タスクの送信には、複数の永続的な書き込みが含まれます。 たとえば、タスクでは、ビジネス データベース内のアプリケーション レコードと状態ストア内の初期レコードの両方を書き込む必要がある場合があります。 これらの書き込みではトランザクションは共有されないため、1 つの書き込みが完了した場合、アプリケーション レコードに状態ストア レコードがない場合や、状態ストア レコードにアプリケーション レコードがない可能性があります。 現在のパターン自体では、このデュアル書き込み問題は解決されません。 一般的なソリューションには、障害時の補正削除を使用した持続的オーケストレーション内での書き込み、 トランザクション送信トレイ パターンの適用、またはアプリケーション独自のタスク ID などの安定した識別子を使用して、各書き込みを安全に繰り返し可能にする方法が含まれます。

  • ワークフローと状態のバージョン管理。 実行時間の長いタスクはデプロイにまたがることができるため、ワークフロー ロジックまたは永続化された状態を変更すると、実行中の作業の再生、回復、または補正を防ぐことができます。 両方のコントラクトをバージョン化し、アクティブなタスクがいずれもそれらに依存しなくなるまで、互換性のあるコードと状態管理を保持します。

  • 補償結果。 補正トランザクションは、途中で完了、失敗、またはストールする可能性があります。 Scheduler が保持するステート マシンは、これらすべての状態を表す必要があります。 エラーが唯一の終了状態である場合、スタック補正は補正が実行される前に失敗したステップと同じように見え、オペレーターは介入する必要がある信号を失います。 状態ストアのスキーマでは、補償の進行中、補償の完了、補償の失敗を、単一のエラー状態にまとめるのではなく、区別します。

  • スーパーバイザーの実行間隔。 スーパーバイザを実行する頻度は、意図的なトレードオフです。 失敗したステップやタイムアウトしたステップによって作業が長時間ブロックされないよう、十分な頻度で実行する必要がありますが、状態ストアに負荷やコストをかける原因になるほど頻繁であってはなりません。 一般的なステップ期間と、スタックしたステップの許容される検出遅延に対して間隔を調整し、ワークフローボリュームの増加に合わせて再検討します。

  • ステップの冪等性。 エージェントは、ステップを複数回実行する場合があります。 たとえば、スーパーバイザーは完了時間を延長し、Scheduler に対して、元の実行によってスケジューラが見たことのない効果が既に生成されているステップを再試行するよう求める場合があります。 したがって、各ステップを実装するロジックは べき等である必要があります。

  • 運用の可視性。 パターンのランタイム動作は、同期応答ではなく、状態ストアの遷移にあります。 オペレーターは、状態ストアとワーカーが出力する内容のみを確認できます。 Scheduler、Agents、Supervisor の出力内容と、アラートを発報するしきい値を決定します。

  • スケジューラの再起動と回復。 障害が発生した後にスケジューラが再起動した場合、または Scheduler が実行しているワークフローが予期せず終了した場合、Scheduler は失敗したときに処理していたタスクの状態を特定し、その時点からタスクを再開できる必要があります。 通常、この回復の実装の詳細はシステム固有です。 たとえば、チェックポイント処理されたオーケストレーション ランタイムに基づいて構築された Scheduler は、ランタイムを利用して履歴を再生して再開できますが、カスタム Scheduler は状態ストア自体から進行中の状態を再構築する必要があります。 タスクを回復できない場合は、そのタスクに対して既に実行されている作業を元に戻す必要があり、 補正トランザクションが必要になる場合があります。

このパターンを使用する場合

このパターンは次の状況で使用します。

  • プロセスは分散ワークロードで実行され、 通信エラーと、調整するサービスとリソース全体の運用エラーの両方に対する回復性を維持する必要があります。

  • バックグラウンド ジョブは、リモート サービスまたはリソースを含むステップを含む複数のステップのワークフローを調整します。ワークフロー全体が完了するか、元に戻す必要があります。 一般的な例としては、注文処理やリソースのプロビジョニングなどがあります。 詳細については、「 バックグラウンド ジョブのベスト プラクティス」を参照してください。

このパターンは、次の場合に適さない場合があります。

  • タスクはリモート サービスを呼び出したり、リモート リソースにアクセスしたりしません。 Scheduler、Agent、Supervisor の役割を軽減するための分散障害サーフェスはありません。 このパターンの調整オーバーヘッドにより、回復性の利点なしでコストが増加します。

ワークロード設計

ワークロードの設計で Scheduler Agent Supervisor パターンを使用して、Azure Well-Architected Framework の柱で説明されている目標と原則に対処する方法を評価します。 次の表は、このパターンが各柱の目標をサポートする方法に関するガイダンスを示しています。

柱 このパターンが柱の目標をサポートする方法
信頼性設計の決定は、故障に対するワークロードの回復性を高め、障害の発生後にワークロードを完全な機能状態に回復させるために役立ちます。 このパターンでは、永続的な状態ストアと定期的に実行されるスーパーバイザーを使用して、タイムアウトしたステップや失敗したステップを検出し、復旧を進めます。

- RE: 05冗長性
- RE:07 自己保護
パフォーマンス効率 は、スケーリング、データ、およびコードの最適化を通じて、ワークロード の需要を効率的に満たすのに役立ちます。 このパターンでは、実行時間の長い複数ステップの作業のオーケストレーションが、手順を実行するエージェントから分離されるため、容量を持つエージェントに手順をディスパッチできます。 優先順位の高い作業は、実装が明示的な優先順位シグナルを提供する場合に、優先順位の低い作業よりも先にスケジュールできます。

- PE:05 スケーリングとパーティショニング
- PE:09 クリティカルフロー

このパターンによって柱内にトレードオフが生じる場合は、他の柱の目標に照らして検討してください。

例

この例では、e コマース システムを実装する Web アプリケーションを Microsoft Azure にデプロイします。 ユーザーは Web フロントエンドを介して製品を参照して注文を行い、注文処理パスのバックグラウンド ワーカーは、一時的で長続きの障害が発生しやすいリモート サービスを呼び出します。 注文処理では、Durable Functions、Azure Service Bus、およびAzure Cosmos DBを使用して Scheduler Agent Supervisor パターンを実装します。

サブミット処理は、注文データベースと Cosmos DB の状態ストアに書き込みを行います。また、Durable Functions のオーケストレーターは、保留中の状態レコードを取得し、Service Bus の要求キューと応答キューのペアを介してエージェントに作業を割り当てます。さらに、スーパーバイザーは、期限切れの状態レコードがないか状態ストアを CompleteBy 回スキャンします。

次の図は、Azure ソリューションの概要を示しています。

eコマース注文処理ソリューションの例を示す図。

  1. アプリケーションは、注文を処理する要求をキューに送信します。
  2. 送信プロセスでは、要求を取得し、注文データベースに注文の詳細を挿入し、状態ストアで注文のレコードを生成します。
  3. Scheduler は状態ストアで LockedBy が null に設定されている注文を検索し、Scheduler のワークフロー ロジックが順序を処理します。
  4. ワークフロー ロジックは、メッセージ キューを介してエージェントに要求を送信し、エージェントから応答を受信します。
  5. ワークフロー タスクでは、エージェントを使用してリモート サービスを呼び出します。
  6. Supervisor は、期限切れの CompleteBy 値を持つ注文を検索し、この値を更新して Scheduler がプロセスを再試行できるようにします。

送信

顧客が注文を行うと、Web フロントエンドは注文メッセージを Service Bus キューに投稿します。 送信関数は 、PeekLock モードでメッセージを受信し、注文の詳細を注文データベースに挿入し、注文プロセスの状態ストア レコードを作成します。

Orders データベースと Azure Cosmos DB で作成したデータベースは異なるリソースであり、同じトランザクションを共有していないため、関数は各書き込みをそれぞれ独立して冪等として扱います。 この関数は、順序 ID を安定したキーとして使用し、存在しない場合はいずれかのレコードを作成し、変更できない注文データがメッセージと一致することを確認した後にのみ、既存のレコードを受け入れます。 データの競合が発生すると、関数はレコードを上書きするのではなく、メッセージをデッドレターキューに送り、オペレーターに通知します。

レコードには、次のフィールドが含まれています。

フィールド 説明
OrderID Azure Cosmos DB ドキュメント ID とパーティション キーとして使用される orders データベース内の注文の ID。
LockedBy 順序を処理するオーケストレーションの試行固有のインスタンス ID。 複数の Scheduler オーケストレーションが実行されている可能性がありますが、条件付き状態遷移では、1 つの注文を要求するアクティブな試行のみが許可されます。
CompleteBy 注文を処理する必要がある時間。
ProcessState 注文を処理しているタスクの現在の状態。 可能性のある状態は次のとおりです。
- Pending: 注文は作成されますが、処理は開始されていません。
- Processing: 注文は現在処理中です。
- Processed: 注文が正常に処理されました。
- Error: 注文処理に失敗しました。
FailureCount 注文に対して記録された失敗またはタイムアウトした処理試行の数。

申請アクティビティは、最初にレコードを書き込むときに、新しい注文から OrderID をコピーし、 LockedBy と CompleteBy を nullに設定し、 ProcessState を Pendingに設定し、 FailureCount を 0に設定します。

Note

この例では、注文処理ロジックは意図的に単純であり、リモート サービスを呼び出す 1 つのステップがあります。 より複雑な複数のステップのシナリオでは、送信アクティビティはステップごとに 1 つの状態ストア レコードを作成し、パーティション キーとして OrderID を保持しますが、 {OrderID}:{StepID}などの一意の項目 ID を使用するため、Scheduler と Supervisor は各ステップの状態を個別に推論できます。

Scheduling

Scheduler は、Durable Functions オーケストレーターです。 スターター関数は、LockedByが null でProcessStateがPendingレコードのAzure Cosmos DBをポーリングします。 この関数は、 OrderID と次の試行番号から試行固有のオーケストレーション インスタンス ID を作成します。 条件付き更新では、スターターがオーケストレーションをスケジュールする前に、 ProcessState が Processing に設定され、そのインスタンス ID に LockedBy されます。 この要求により、2 人のスターターが同じ試行をスケジュールできなくなります。

また、オーケストレーションからの各更新では、 LockedBy がそのインスタンス ID と一致することも確認されます。 このチェックにより、期限切れの試行が置換試行の状態を変更するのを防ぎます。 クロスオーダー並列処理は、1 つの順序内の並列処理ではなく、多数のオーケストレーション インスタンスを同時に実行することです。 オーケストレーションは CompleteBy を設定し、ワークフローを駆動します。

オーケストレーターは注文データベースから注文の詳細を取得し、アクティビティ関数のシーケンスとしてワークフローを実行します。 ステップでリモート サービスが必要になると、エージェントが呼び出されます。

Execution

エージェントは、作業が有効期間が短く、同じ関数アプリで実行されている場合はアクティビティ関数にすることも、別のランタイムまたは信頼境界を越えて実行する場合は、Service Bus要求/応答キュー ペアを介して個別のワーカーに到達することもできます。 どちらの場合も、オーケストレーターはエージェントの応答に対して 永続的タイマー を競合し、 CompleteBy 期限を検出します。

エージェントがService Bus経由で到達すると、キューによってトリガーされる関数は応答を受け取り、Durable Functions クライアントを使用して、オーケストレーション インスタンス ID と安定したイベント ID を含む外部イベントを発生させます。 オーケストレーターは、重複の検出を有効にし、各要求で安定したMessageIdを設定することで外部イベントを重複除去するため、Service Busは再試行によって発生した重複を破棄できます。

永続的タイマーが起動する前にエージェントがリモート サービスから応答を受信した場合、エージェントはオーケストレーターに結果を返します。 オーケストレーターは、現在のオーケストレーションを引き続き識別する場合にのみ、ProcessStateLockedByステップを完了し、Processedに更新します。 タイマーが最初に起動すると、オーケストレーターはステップを失敗として扱い、待機を停止し、状態レコードを変更せずに完了します。

エージェントは、自身の期限が過ぎると、新たな副作用の発生を協調的に停止しますが、すでに進行中の処理は継続される場合があります。 その後、状態ストア レコードは Processing 状態のままで、 CompleteBy 値が期限切れになり、Supervisor は復旧を調整できます。 重複して実行された試行が副作用を重複して発生させたり競合したりするのを防ぐには、冪等性または対象側で強制されるフェンシングトークンを使用します。

エージェントは、リモート サービスへの接続中に回復不能で一時的でない障害を検出すると、オーケストレーターにエラー応答を返します。 オーケストレーターは ProcessState を Error に設定し、オペレーターに警告するイベントを発生させます。オペレーターは、エラーを調査し、失敗した処理手順を再送信できます。

監督

Supervisor は、期限切れのCompleteByProcessing状態の注文について、Azure Cosmos DB状態ストアに定期的にクエリを実行します。 OrderIDはパーティション キーであるため、このクエリは、ProcessStateとCompleteByがインデックス付けされている場合でも、すべての物理パーティションに到達します。 このプロセスは、各スキャンを CompleteBy 時間枠、最大結果数、継続トークンページングによってバインドし、その要求ユニット (RU) の料金を監視します。

大規模なワークロードでは、Supervisor のアクセス パターン用にパーティション分割された個別の復旧インデックスまたはキューが維持されます。 Supervisor は、期限切れのレコードを見つけると、期限切れの LockedBy 値を確認する条件付き更新を使用してから FailureCountをインクリメントします。 FailureCountが設定されたしきい値を下回ると、スーパーバイザはLockedByをnullにリセットし、新しい有効期限でCompleteByを更新し、ProcessStateをPendingに戻します。これにより、スターターは新しい試行をスケジュールできます。 FailureCountしきい値を超えた場合、Supervisor は障害を非一時的なものとして扱い、ProcessStateをErrorに設定し、オペレーターに警告するイベントを発生させます。

Note

Supervisor は、スキャンが短くて軽量な場合はタイマーによってトリガーされる関数として、またはスキャンでカスタム コンテナー イメージ、実行時間の長い実行、またはサイドカーが必要な場合にスケジュールされたAzure Container Apps ジョブとしてホストされます。 どちらのオプションも cron スタイルのスケジュールで実行され、Supervisor が実行する定期的で有効期間の短い作業に適しています。 タイマー トリガーは、1 つの関数アプリでスケールアウトされたインスタンス間でストレージ ロックを使用します。 重複する可能性のある独立したデプロイまたは Container Apps ジョブは、前に説明した条件付き回復要求を使用するか、 リーダー選択パターンを使用して調整できます。

ステータス報告

オーケストレーターは、注文を送信したアプリケーションに進行状況と最終状態に関する情報を保持する必要もあります。図には表示されません。 アプリケーションとオーケストレーターは意図的に分離されます。 アプリケーションは、どのオーケストレーション インスタンスが順序を処理しているのかを認識せず、どのアプリケーション インスタンスが注文を送信したかわからない。 この切り離しにより、オーケストレーターは進行状況の更新を同期的に返すことはできません。

注文の状態を報告するために、送信する各アプリケーションは、アクセス制御された独自のService Bus応答キューを提供します。 送信アクティビティに送信される要求には、そのキューの識別子が含まれます。送信アクティビティは、その識別子を注文の状態ストアのレコードに記録します。これにより、オーケストレーターはブロードキャストするのではなく、適切なキューに送信できます。 その後、オーケストレーターは、 受信した要求、 注文が完了した、 注文が失敗した などのステータス メッセージを、 OrderID を含めてそのキューに投稿します。これにより、アプリケーションは各メッセージを元の要求に関連付けることができます。

サポート テクノロジ

パターンの論理ロールを、ワークフローと運用の要件に合ったサービスにマップします。

  • Scheduler: コード優先のオーケストレーションには Durable Functions を使用し、ビジュアルワークフローとコネクタベースの統合には Azure Logic Apps を使用します。

  • エージェント メッセージング:非同期の要求と応答のメッセージングには、Service Bus キューを使用します。

  • 状態ストア:ドキュメントの状態にAzure Cosmos DBを使用するか、リレーショナル状態とクロスレコード トランザクションのAzure SQL Databaseを使用します。

  • スーパーバイザー: 軽量なスキャンには Functions タイマー トリガー を使用し、コンテナー ランタイムが必要な場合は Container Apps ジョブ を使用します。

  • 補償ログ: 補償レコードをタスクの状態と共に、または Azure Table storage もしくは Blob Storage に保存します。

次のステップ

このパターンを実装する場合は、次のパターンも関連している可能性があります。

  • 再試行パターン。 エージェントは、このパターンを使用して、リモート サービスまたはリソースにアクセスし、以前に失敗した操作を透過的に再試行できます。 エラーの原因が一時的であると予想され、再試行によって修正できる場合に使用します。

  • サーキットブレーカーパターン。 リモート サービスまたはリソースに接続するエージェントは、このパターンを使用して、修正に時間がかかる障害を処理できるため、繰り返し呼び出しが応答する可能性が低い依存関係に対して積み重なりません。

  • 補償トランザクションパターン。 Scheduler がワークフローを正常に完了できない場合は、既に実行されている作業を元に戻す必要があります。 補償トランザクション パターンは、Scheduler が調整する長時間にわたるビジネス プロセスで一般的な、結果整合性モデルに従う操作について、その作業を取り消す方法を説明します。

  • リーダー選定パターン。 複数の Supervisor インスタンスが同時に実行される場合は、同じ失敗した手順を復旧するために競合しないように調整する必要があります。 リーダー選定パターンでは、その作業に対して 1 つのコーディネーターを選択する方法について説明します。