web-dev-qa-db-ja.com

REST)で非同期操作を処理する方法

RESTで非同期操作を処理するためのアプローチと、それらの長所と短所を理解する必要があります。私が見つけたいくつかのアプローチ:

  1. リソースベース:操作のステータスがステータスとしてモデル化される場合。ユーザーが非同期のREST呼び出し(PUT、POSTなど)を行うと、AcceptedまたはIn-Progress応答(202)を取得します。さらに、ステータスURIはGETを介して繰り返しポーリングされ、操作の実行からのステータス/進行状況/メッセージを確認します。

    質問:このリソースはサーバーでどのくらいアクティブにする必要がありますか?クライアントが操作の間に大きな間隔でポーリングする場合、どのようにステータスを返しますか?実行ステータスを永続化することは機能するようです。しかし、いつアーカイブ/削除するのか、この種の標準的なアプローチはどのくらい持続しますか?

  2. コールバックベース:コールバックURIを持つために非同期リクエストが必要な場合。リクエストは非同期で処理され、完了すると、操作ステータス/結果を使用してコールバックURIが呼び出されます。

    質問:これはよりエレガントで、サーバー側のオーバーヘッドが少ないようです。しかし、コールバックサーバーが断続的にダウンしたり、応答しなかったりするシナリオを処理するにはどうすればよいでしょうか。コールバックURIが再試行構成も提供する典型的な再試行を実装しますか?このアプローチに他の欠点はありますか?

  3. サーブレット3.0非同期サポート: HTTPクライアントがJavaサーブレットに接続する場合。サーブレットは、明示的に閉じられるまで、また閉じられたクライアントとサーバーが非同期で通信できるようになるまで開いたままになります。

    質問:サーブレット3.0仕様なので、Spring RESTの実装であるJerseyは、現時点ではこのアプローチを利用していないと思います。同様のアプローチまたはそれを可能にする方法へのポインタを利用する特定のREST実装はありますか?

  4. 他のアプローチ、多分商業的なアプローチ?

13
harsh

Spring 3.2以降は、サーブレット3.0の非同期機能をサポートしています。 春のブログ から:

callableを返すように変更することで、既存のコントローラーメソッドを非同期にすることができます。たとえば、ビュー名を返すコントローラーメソッドは、代わりにCallableを返すことができます。 Personというオブジェクトを返す@ResponseBodyは、代わりにCallableを返すことができます。また、他のコントローラーの戻り値タイプについても同じことが言えます。

Jersey 2+は、非同期サーバーもサポートしています。リファレンスドキュメントの 非同期サービスとクライアント の章を参照してください。

6
matsev

アプローチは、最初のリクエストから操作の終了までの時間差に依存すると思います。

  • 短時間の操作(<10秒)の場合は、要求を開いたままにして、操作が終了したときに応答を返します。
  • 長時間の操作(<30m)の場合は、サーブレット3.0またはCometモデルを使用します。
  • 非常に長い操作(数時間、数日)の場合、私にとっては、クライアントベースのポーリングまたは大きなタイムアウトのあるCometだけで十分です。
3
user2256686

私は今同じ状況に取り組んでおり、Locationヘッダー応答を使用して、ステータスを確認するために監視できるリソースを提供する一般的なアプローチを見つけました(もちろんポーリングによって)。それが最善のようですが、私の場合、リソースを作成していないため、ステータスを確認する場所がありません(非同期プロセスはキャッシュページを作成するだけです)。

いつでも独自のヘッダーを使用して、操作を完了するための推定時間を与えることができます。とにかく、私はRetry-Afterヘッダーを使用して推定時間を与えることを考えています。皆さんはどう思いますか?

0
javivelasco

これは古いことは知っていますが、ここでチャイムを鳴らして、ステートレス環境でスケールアウトできるものが必要な場合は、最初のオプションを選択する必要があると思いました。基盤となる操作はどこでも実行でき、結果をredisのようなものにすると、クライアントが後続のポーリング要求を行うWebサーバーには関係ありません。通常、クライアントに送信した応答にポーリング間隔を設定します。結果の準備ができたら、URIに結果のIDを含むSEEOTHERをクライアントに返します。

0
robert_difalco