web-dev-qa-db-ja.com

長時間実行REST API with queues

REST APIを実装しています。このAPIは、長時間実行される複数のバックエンドタスクを開始します。RESTfulWebサービスクックブックを読んでおり、推奨はHTTP 202/Accepted with a Content-Locationを返すことです処理中のタスクを指すヘッダー(例: http://www.example.org/orders/tasks/1234 )、クライアントにこのURIをポーリングして、長時間実行されるタスクの更新を求めます。

アイデアは、REST APIがメッセージをすぐにキューに投稿し、バックグラウンドワーカーの役割がキューからメッセージを取得し、キューを使用して複数のバックエンドタスクをスピンアップすることです。このアプローチでは、一意のIDをタスクに割り当て、続いてクライアントがContent-Location URIにGETを発行することでタスクのステータスを要求する方法がわかります。

REST APIがすぐにキューに投稿する場合は、GUIDを生成し、キューに追加されるメッセージの属性としてアタッチできますが、リクエストのステータスを取得するのは面倒です。

もう1つのオプションは、REST APIにデータベースにエントリを追加し(新しい注文IDで注文をしましょう)、初期ステータスを設定してから、メッセージをAPIは、クライアントがタスクのステータスを確認するときに使用するために、Content-LocationヘッダーのURIでこの新しい注文IDを返します。

どういうわけか、最初にデータベースエントリを追加してから、メッセージをキューに追加すると逆に見えますが、要求をキューに追加するだけでは進捗を追跡するのが難しくなります。

推奨されるアプローチは何ですか?

あなたの洞察に感謝します。

52
user2079172

あなたのシステムは次のように見えると思います。クライアントからリクエストを受信するRESTサービスがあります。要求をビジネスロジックが理解できるコマンドに変換します。これらのコマンドをキューに入れます。これらのコマンドを処理してキューから削除し、結果をクライアントに応答できるRESTサービスに送信できる単一または複数のワーカーがあります。

長時間実行するタスクによってクライアント接続がタイムアウトするため、応答を送信できないという問題。したがって、できることは、コマンドをキューに入れてポーリングリンクを追加した後、承認された202を送信することです。これにより、クライアントは変更をポーリングできます。タスクには複数のサブタスクがあるため、ステータスの変更が保留中および完了しただけでなく、進行状況があります。

  1. ポーリングに固執する場合は、新しいRESTリソースを作成する必要があります。このリソースには、長時間実行されているタスクの実際の状態と進行状況が含まれます。つまり、この情報をデータベースに保存する必要があるため、RESTサービスはGET /tasks/23461/statusなどのリクエストに応答できます。これは、サブタスクまたはタスク全体が完了すると、ワーカーがデータベースを更新する必要があることを意味します。
  2. RESTサービスがデーモンとして実行されている場合、進行状況によって通知できるため、データベースにタスクステータスを保存することはワーカーの責任ではありません。この種類のRESTサービスは、情報をメモリに保存することもできます。
  3. Websocketを使用してクライアントに通知することにした場合は、通知サービスを作成できます。 RESTでは、タスクIDで応答する必要があります。その後、websocket接続でこのタスクIDを送り返すので、通知サービスは特定のタスクのイベントにサブスクライブしているwebsocket接続を認識します。その後、RESTサービスは必要なくなりますが、クライアントが接続を閉じない限り、websocket接続を介して進行状況を送信できます。
  4. これらのソリューションは、次の方法で組み合わせることができます。 RESTサービスにタスクリソースを作成させるので、ポーリングリンクを使用して進行状況にアクセスできます。その後、202で識別子を送り返し、websockets接続を介して送り返します。したがって、通知サービスを使用してクライアントに通知できます。進行状況により、ワーカーはRESTサービスに通知します。これにより、GET /tasks/23461/statusなどのリンクが作成され、通知サービスを介してそのリンクがクライアントに送信されます。その後、クライアントはリンクを使用してステータスを更新できます。

RESTサービスがデーモンとして実行される場合、最後の方法が最善の解決策だと思います。これは、Websocket、ポーリング、SSEなど、必要なものを使用できる専用の通知サービスに通知責任を移動できるためです。 RESTサービスを強制終了せずに折りたたむことができるため、RESTサービスは安定した高速なままです。 202を使用して手動更新リンクも送り返す場合、クライアントは手動更新を実行できます(人間が制御するクライアントを想定しています)。そのため、通知サービスが利用できない場合、グレースフルデグラデーションなどが発生します。通知サービスはタスクについて何も知らず、クライアントにデータを送信するだけなので、通知サービスを維持する必要はありません。ワーカーは、通知の送信方法とハイパーリンクの作成方法について何も知る必要はありません。ほぼ純粋なRESTクライアントになるため、クライアントコードの保守も簡単になります。唯一の追加機能は、頻繁に変更されない通知リンクのサブスクリプションです。

54
inf3rno