§非同期レスポンスの処理
§非同期レスポンスはなぜ必要か?
これまでは、web クライアントに送信するレスポンスをすぐに生成できることとしていました。しかし、常にこのような場合だけではありません。レスポンスは、高価な計算や長い web サービスの呼び出しに依存するかもしれません。
Play 2.0 の仕組み上、アクションの実行は可能な限り早く (言い換えると、ノンブロッキングに) 完了しなければなりません。では、レスポンスがまだ生成可能でないときに、一体何を返すべきでしょうか? それは、レスポンスの約束 (promise) です!
Promise<Result>
という約束は、最終的に Result
型の値によって果たされます。通常の Result
のかわりに Promise<Result>
を返すことで、何もブロックせずに即座に結果を返すことができます。Play は後に Promise が果たされたときに、内包された結果を自動的にクライアントへ送信します。
web クライアントはレスポンスを待っている間ずっとブロックされますが、その間でもサーバ側の処理は全くブロックされないため、計算リソースを他のクライアントのために使うことができます。
§Promise<Result>
の生成
Promise<Result>
を生成するためには、元となる Promise
、つまり結果を計算するために必要な値についての Promise が先に必要になります。
Promise<Double> promiseOfPIValue = computePIAsynchronously();
Promise<Result> promiseOfResult = promiseOfPIValue.map(
new Function<Double,Result>() {
public Result apply(Double pi) {
return ok("PI value computed: " + pi);
}
}
);
ノート: Java で関数合成を記述することは現状では本当に面倒です。しかし、これは Java が ラムダ記法 をサポートすれば改善されるでしょう。
Play 2.0 の非同期処理に関する API 呼び出しは Promise
を返します。例えば、play.libs.WS
API を使って外部の Web サービスを呼び出す場合や、play.libs.Akka
API 経由で Akka を使った非同期タスクを実行したり、アクターと通信したりする場合がそうです。
コードブロックを非同期で実行して Promise
を得る簡単な方法は、play.libs.Akka
ヘルパーを利用することです。
Promise<Integer> promiseOfInt = Akka.future(
new Callable<Integer>() {
public Integer call() {
return intensiveComputation();
}
}
);
ノート: ここでは、非常に時間のかかる計算を別スレッドで実行しています。その他に、このような計算を Akka remote を利用してバックエンドサーバのクラスタ上で実行することもできます。
§AsyncResult
これまでは Results.Status
を使ってきましたが、非同期な結果を送信するためには、結果をラップする Results.AsyncResult
が必要です。
public static Result index() {
Promise<Integer> promiseOfInt = Akka.future(
new Callable<Integer>() {
public Integer call() {
return intensiveComputation();
}
}
);
return async(
promiseOfInt.map(
new Function<Integer,Result>() {
public Result apply(Integer i) {
return ok("Got result: " + i);
}
}
)
);
}
ノート:
async()
はPromise<Result>
からAsyncResult
を作成するためのヘルパーメソッドです。
次ページ: HTTP レスポンスのストリーミング