§非同期レスポンスの処理
§非同期レスポンスはなぜ必要か?
これまでは、web クライアントに送信するレスポンスをすぐに生成できることとしていました。しかし、常にこのような場合だけではありません。レスポンスは、高価な計算や長い web サービスの呼び出しに依存するかもしれません。
Play 2.0 の仕組み上、アクションの実行は可能な限り早く (言い換えると、ノンブロッキングに) 完了しなければなりません。では、レスポンスがまだ生成可能でないときに、一体何を返すべきでしょうか? それは、レスポンスの約束 (promise) です!
Promise[Result]
という約束は、最終的に Result
型の値によって果たされます。通常の Result
のかわりに Promise[Result]
を返すことで、何もブロックせずに即座に結果を返すことができます。Play は後に Promise が果たされたときに、内包された結果を自動的にクライアントへ送信します。
web クライアントはレスポンスを待っている間ずっとブロックされますが、その間でもサーバ側の処理は全くブロックされないため、計算リソースを他のクライアントのために使うことができます。
§Promise[Result]
の生成
Promise[Result]
を生成するためには、元となる Promise
、つまり結果を計算するために必要な値についての Promise が先に必要になります。
val promiseOfPIValue: Promise[Double] = computePIAsynchronously()
val promiseOfResult: Promise[Result] = promiseOfPIValue.map { pi =>
Ok("PI value computed: " + pi)
}
Play 2.0 の全ての非同期処理に関する API 呼び出しは Promise
を返します。例えば、play.api.libs.WS
API を使って外部の Web サービスを呼び出す場合や、play.api.libs.Akka
API 経由で Akka を使った非同期タスクを実行したり、アクターと通信したりする場合がそうです。
コードブロックを非同期で実行して Promise
を得る簡単な方法は、play.api.libs.concurrent.Akka
ヘルパーを利用することです。
val promiseOfInt: Promise[Int] = Akka.future {
intensiveComputation()
}
ノート: ここでは、非常に時間のかかる計算を別スレッドで実行しています。その他に、このような計算を Akka remote を利用してバックエンドサーバのクラスタ上で実行することもできます。
§AsyncResult
これまでは SimpleResult
を使ってきましたが、非同期な結果を送信するためには、SimpleResult
をラップする AsyncResult
が必要です。
def index = Action {
val promiseOfInt = Akka.future { intensiveComputation() }
Async {
promiseOfInt.map(i => Ok("Got result: " + i))
}
}
ノート:
Async { }
はPromise[Result]
からAsyncResult
を作成するためのヘルパーメソッドです。
§タイムアウト処理
何らかの問題が発生したとき web ブラウザが延々とブロックしてしまうことを避けるために、タイムアウトが役立つことが多々あります。そのような場合、 Promise と Promise のタイムアウトを簡単に組み合わせることができます。
def index = Action {
val promiseOfInt = Akka.future { intensiveComputation() }
Async {
promiseOfInt.orTimeout("Oops", 1000).map { eitherIntorTimeout =>
eitherIorTimeout.fold(
i => Ok("Got result: " + i),
timeout => InternalServerError(timeout)
)
}
}
}
次ページ: HTTP レスポンスのストリーミング
このドキュメントの翻訳は Play チームによってメンテナンスされているものではありません。 間違いを見つけた場合、このページのソースコードを ここ で確認することができます。 ドキュメントガイドライン を読んで、お気軽にプルリクエストを送ってください。