2.1_Handling asynchronous results
来源:互联网 发布:ocr日文识别软件 编辑:程序博客网 时间:2024/05/17 05:53
Handling asynchronous results
Make controllers asynchronous
Internally, Play Framework is asynchronous from the bottom up. Play handles every request in an asynchronous, non-blocking way.
The default configuration is tuned for asynchronous controllers. In other words, the application code should avoid blocking in controllers, i.e., having the controller code wait for an operation. Common examples of such blocking operations are JDBC calls, streaming API, HTTP requests and long computations.
Although it’s possible to increase the number of threads in the default execution context to allow more concurrent requests to be processed by blocking controllers, following the recommended approach of keeping the controllers asynchronous makes it easier to scale and to keep the system responsive under load.
Creating non-blocking actions
Because of the way Play works, action code must be as fast as possible, i.e., non-blocking. So what should we return as result if we are not yet able to generate it? The response is a future result!
A Future[Result]
will eventually be redeemed with a value of type Result
. By giving a Future[Result]
instead of a normal Result
, we are able to quickly generate the result without blocking. Play will then serve the result as soon as the promise is redeemed.
The web client will be blocked while waiting for the response, but nothing will be blocked on the server, and server resources can be used to serve other clients.
How to create a Future[Result]
To create a Future[Result]
we need another future first: the future that will give us the actual value we need to compute the result:
import play.api.libs.concurrent.Execution.Implicits.defaultContextval futurePIValue: Future[Double] = computePIAsynchronously()val futureResult: Future[Result] = futurePIValue.map { pi => Ok("PI value computed: " + pi)}
All of Play’s asynchronous API calls give you a Future
. This is the case whether you are calling an external web service using the play.api.libs.WS
API, or using Akka to schedule asynchronous tasks or to communicate with actors using play.api.libs.Akka
.
Here is a simple way to execute a block of code asynchronously and to get a Future
:
import play.api.libs.concurrent.Execution.Implicits.defaultContextval futureInt: Future[Int] = scala.concurrent.Future { intensiveComputation()}
Note: It’s important to understand which thread code runs on with futures. In the two code blocks above, there is an import on Plays default execution context. This is an implicit parameter that gets passed to all methods on the future API that accept callbacks. The execution context will often be equivalent to a thread pool, though not necessarily.
You can’t magically turn synchronous IO into asynchronous by wrapping it in a
Future
. If you can’t change the application’s architecture to avoid blocking operations, at some point that operation will have to be executed, and that thread is going to block. So in addition to enclosing the operation in aFuture
, it’s necessary to configure it to run in a separate execution context that has been configured with enough threads to deal with the expected concurrency. See Understanding Play thread pools for more information.It can also be helpful to use Actors for blocking operations. Actors provide a clean model for handling timeouts and failures, setting up blocking execution contexts, and managing any state that may be associated with the service. Also Actors provide patterns like
ScatterGatherFirstCompletedRouter
to address simultaneous cache and database requests and allow remote execution on a cluster of backend servers. But an Actor may be overkill depending on what you need.
Returning futures
While we were using the Action.apply
builder method to build actions until now, to send an asynchronous result we need to use the Action.async
builder method:
import play.api.libs.concurrent.Execution.Implicits.defaultContextdef index = Action.async { val futureInt = scala.concurrent.Future { intensiveComputation() } futureInt.map(i => Ok("Got result: " + i))}
Actions are asynchronous by default
Play actions are asynchronous by default. For instance, in the controller code below, the { Ok(...) }
part of the code is not the method body of the controller. It is an anonymous function that is being passed to the Action
object’sapply
method, which creates an object of type Action
. Internally, the anonymous function that you wrote will be called and its result will be enclosed in a Future
.
val echo = Action { request => Ok("Got request [" + request + "]")}
Note: Both
Action.apply
andAction.async
createAction
objects that are handled internally in the same way. There is a single kind ofAction
, which is asynchronous, and not two kinds (a synchronous one and an asynchronous one). The.async
builder is just a facility to simplify creating actions based on APIs that return aFuture
, which makes it easier to write non-blocking code.
Handling time-outs
It is often useful to handle time-outs properly, to avoid having the web browser block and wait if something goes wrong. You can easily compose a promise with a promise timeout to handle these cases:
import play.api.libs.concurrent.Execution.Implicits.defaultContextimport scala.concurrent.duration._def index = Action.async { val futureInt = scala.concurrent.Future { intensiveComputation() } val timeoutFuture = play.api.libs.concurrent.Promise.timeout("Oops", 1.second) Future.firstCompletedOf(Seq(futureInt, timeoutFuture)).map { case i: Int => Ok("Got result: " + i) case t: String => InternalServerError(t) }}
Next: Streaming HTTP responses
Found an error in this documentation? The source code for this page can be found here. After reading thedocumentation guidelines, please feel free to contribute a pull request.
- 2.1_Handling asynchronous results
- @Results
- play framework2学习之旅<2.1>Actions, Controllers and Results
- Best results
- Struts2-Results
- OTB Results
- <global-results>
- Struts2--Results
- Asynchronous Processing
- jstestdrive / asynchronous
- Asynchronous Servlets
- asynchronous@tornado
- Asynchronous glReadPixels
- Asynchronous programming
- CSS Instant Results
- Visual Basic2005 Instant Results
- luence Displaying search results
- 全局result(global-results)
- QSortFilterProxyModel
- android动态加载(二)
- C# winform或控制台Properties.Settings.Default的使用及存储位置
- 微信菜单定义小工具
- 【重学《C++Primer第四版》】第二章、变量和基本类型
- 2.1_Handling asynchronous results
- 2次创业经验谈(想创业想做事的人不要错过)
- 2015阿里前端实习在线笔试题
- (五)Unity5.0新特性------unity中编写脚本
- 《世界是数字的》读书笔记(计算机科普知识)
- 基于django的博客和论坛的整合
- iOS开发者证书-详解/生成/使用
- Struts2----拦截器
- LeetCode #Reverse Number#