§非同期レスポンスの処理
§コントローラを非同期にする
内部的には、Play Framework は根本から非同期です。Play はあらゆるリクエストを非同期かつノンブロッキングに取り扱います。
デフォルトの設定は非同期なコントローラに最適化されています。別の言い方をすると、アプリケーションコードは、例えばコントローラのコードで命令の実行を待ってしまうなど、ブロッキングするコントローラを避けなければなりません。ブロッキング操作の一般的な例は、JDBC 呼び出し、streaming API、HTTP リクエスト、そして長時間の計算です。
ブロッキングコントローラでもより多くのリクエストを並列に処理できるよう、デフォルト実行コンテキストのスレッド数を増強することもできますが、推奨されるアプローチに従ってコントローラを非同期に保つことで、容易にスケールし、負荷時でもシステム応答を維持することができます。
§ノンブロッキングなアクションの作成
Play では、例えばノンブロッキングなどのように、アクションコードはできる限り速くなければなりません。それでは、まだ処理結果を計算できていない場合にアクションは何を返すべきでしょうか? Result の promsie を返すべきです!
Promise<Result>
は、最終的に Result
型の値に置き換えられます。通常の Result
の代わりに Promise<Result>
を使うことで、なにもブロックせず速やかにアクションからリターンすることができます。その後、promise が置き換え可能になり次第、Play は Result を提供します。
レスポンスを待つ間に web クライアントはブロックされますが、サーバではなにもブロックされず、他のクライアントにサービスを提供するためにリソースを使うことできます。
§Promise<Result>
の生成
Promise<Result>
を生成するためには、まず別の promise が必要です: この promise は Result を計算するために必要な実際の値を提供します。
Promise<Double> promiseOfPIValue = computePIAsynchronously();
Promise<Result> promiseOfResult = promiseOfPIValue.map(pi ->
ok("PI value computed: " + pi)
);
Play の非同期 API メソッドは Promise
を提供します。これは、play.libs.WS
API を使って外部の Web サービスを呼び出す場合や、play.libs.Akka
を使って Akka を使った非同期タスクを実行したり、アクターと通信したりする場合などが該当します。
promise()
ヘルパーを使うと、簡単にコードブロックを非同期で実行して Promise
を取得できます:
Promise<Integer> promiseOfInt = Promise.promise(() -> intensiveComputation());
注意: どのスレッドコードがどの promise を実行しているか理解することが重要です。ここでは、集中的な計算は別のスレッドで実行されることになります。
同期 IO を
Promise
で包んで魔法のように非同期にすることはできません。ブロッキング操作を避けるようアプリケーションアーキテクチャを変更できなければ、様々な場所でこの操作が実行され、スレッドがブロックされます。このため、操作をPromsie
で包むだけではなく、期待する並列処理を取り扱うために充分なスレッドが設定されている別の実行コンテキストで実行されるよう、この操作を設定する必要があります。詳しくは Play のスレッドプールを理解する を参照してください。ブロッキング操作に Actor を使うのも便利です。Actor はタイムアウトおよび失敗の取り扱い、ブロッキング実行コンテキストの設定、そしてサービスに関連し得るあらゆる状態の管理のための、洗練されたモデルを備えています。また、Actor は同時に発生するキャッシュおよびデータベースへのリクエストに対応し、バックエンドサーバのクラスタ上でリモート実行できる
ScatterGatherFirstCompletedRouter
パターンを備えています。ただし、Actor は要件に対してやり過ぎかも知れません。
§非同期な Result
あとから作成される Result
を返すことになります。非同期に Result を返すため、アクションは Promise<Result>
を返す必要があります:
public Promise<Result> index() {
return Promise.promise(() -> intensiveComputation())
.map((Integer i) -> ok("Got result: " + i));
}
§アクションはデフォルトで非同期
Play の actions はデフォルトで非同期です。例えば、以下のコントローラコードで返される Result
は、内部的には promise に包まれています:
public Result index() {
return ok("Got request " + request() + "!");
}
注意: アクションコードが
Result
またはPromise<Result>
のどちらを返そうとも、返却される各種オブジェクトは内部的に同じように取り扱われます。ただ一種類の非同期なAction
があるだけで、(同期的なものと非同期的なものの) 二種類があるわけではありません。Promise
を返却するのは、ノンブロッキングなコードを書くためのテクニックです。
Next: HTTP レスポンスのストリーミング
このドキュメントの翻訳は Play チームによってメンテナンスされているものではありません。 間違いを見つけた場合、このページのソースコードを ここ で確認することができます。 ドキュメントガイドライン を読んで、お気軽にプルリクエストを送ってください。