いくつかの仮定:
1) 最後から 2 行目の HTTP 呼び出しがブロックされます
2) リダイレクトが Http 呼び出しからの応答を待つ必要があるかどうかはわかりませんが、そうすると思います。
リクエストを処理するスレッドをブロックしないように、ブロッキング呼び出しを別のスレッドに移動する必要があります。Play ドキュメントはこれについて非常に具体的です。Akka.future
と組み合わせた機能がAsync
役立ちます。
コントローラーコード:
1 def deleteNode(nodeId: Long) = Action { request =>
2 Async{
3 val response = Akka.future( BusinessService.businessLogic(nodeId) )
4
5 response.map { result =>
6 result map {
7 Redirect( routes.NodeRender.listNodes)
8 } recover {
9 InternalServerError("Failed due to ...")
10 } get
11 }
12 }
13}
これは PHP よりも少し多くなりますが、マルチスレッドです。
3 行目に渡されたコードAkka.future
は、将来別のスレッドを使用して呼び出されます。ただし、 への呼び出しAkka.future
はすぐに a を返しますFuture[Try]
(ビジネス メソッドの戻り値の型については、以下を参照してください)。つまり、変数response
の型はFuture[Try]
. 5 行目のメソッドへのmap
呼び出しは、マップ ブロック内のコードを呼び出すのではなく、そのコード (6 ~ 10 行目) をコールバックとして登録します。スレッドは 5 行目でブロックせずFuture
、ブロックに戻りますAsync
。Async
ブロックは Play に a を返し、それAsyncResult
は Play に Future が完了したときにコールバックのために自分自身を登録するように指示します。
その間、他のスレッドがBusinessService
3 行目から呼び出しを行い、バックエンド システムに対して行った HTTP 呼び出しが返されると、response
3 行目の変数は「完了」します。つまり、6 ~ 10 行目のコールバックが完了します。呼ばれます。 には抽象result
型があり、サブクラスはとの 2 つだけです。が成功した場合、メソッドは 7 行目を呼び出し、それを new でラップします。が失敗した場合、map メソッドは失敗を返します。8行目のメソッドは反対のことをしています。map メソッドの結果が成功の場合は、成功を返します。それ以外の場合は、9 行目を呼び出して( ! ではなく) でラップします。への呼び出しTry
Success
Failure
result
map
Success
result
recover
Success
Failure
get
10 行目のメソッドは、からリダイレクトまたはエラーを取得しSuccess
、その値を使用しAsyncResult
て Play が保持している を完成させます。次に Play は、応答の準備ができており、レンダリングして送信できるというコールバックを取得します。
このソリューションを使用すると、着信要求を処理するスレッドがブロックされなくなります。たとえば 4 コアのマシンでは、Play には受信リクエストを処理できるスレッドが 8 つしかないため、これは重要です。少なくともデフォルト構成を使用している場合は、新しいものは生成されません。
ビジネス サービス オブジェクトのコードは次のとおりです (コードのほとんどをコピーしたものです)。
def businessLogic(nodeId: Long): Future[Try] {
val commitDocument = Json.toJson(
Map(
"delete" -> Seq( Map( "id" -> toJson( nodeId)))
))
val commitSend = Json.stringify( commitDocument)
val commitParams = Map( "commit" -> "true", "wt" -> "json")
val headers = Map( "Content-type" -> "application/json")
val sol = host( "127.0.0.1", 8080)
val updateReq = sol / "solr-store" / "collection1" / "update" / "json" <<?
commitParams <:< headers << commitSend
val commitResponse = Http( updateReq)()
Success(commitResponse) //return the response or null, doesnt really matter so long as its wrapped in a successful Try
}
プレゼンテーション ロジックとビジネス ロジックは完全に切り離されています。
詳細については、 https://speakerdeck.com/heathermiller/futures-and-promises-in-scala-2-dot-10およびhttp://docs.scala-lang.org/overviews/core/futures.htmlを参照してください。