Are there any benefits in using non-async actions in Play Framework 2.2?

拥有回忆 提交于 2019-11-26 16:56:21

问题


The Play 2.2 documentation states that:

Because of the way Play works, the action code must be as fast as possible (ie. 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. Then, Play will serve this 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.

Actions that return a Future are created Action.async, as opposed to Action.apply for normal, non-async actions.

Is there any benefit on having non-async Actions? It strikes me that the best way to ensure that none of my Actions are going to block is to declare all of them using Action.async.

In fact, according to the Play Framework 2.3 documentation it looks like in Play 2.3 all actions are async:

Note: Both Action.apply and Action.async create Action objects that are handled internally in the same way. There is a single kind of Action, 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 a Future, which makes it easier to write non-blocking code.


回答1:


Just because you might use Action.async, doesn't automatically mean you're not blocking. It all depends on whether you're using blocking API or not.

Play 2.2 seems to work the same way as Play 2.3 in this manner. There isn't really a difference between Action.apply and Action.async, other than their signatures. Action.async expects some block of code that returns a Future[Result], while Action.apply expects a block of code that returns a Result. Action.apply converts that block: => Result into Future[Result] by simply calling Future.successful(block). (There is a little more work that goes on before calling Future.successful, but this is the gist of it.)

So the use cases for each boil down to the API you're using. For example JDBC vs ScalikeJDBC-async, blocking vs. non-blocking database APIs. Let's say you're fetching a user from the database and sending it back to the client as json.

The signature of a typical JDBC-backed function might look like this (ignoring failures to simplify):

def read(id: Long): User

Your controller function might then look like this:

def read(id: Long) = Action {
    Ok(Json.toJson(User.read(id))
}

This is roughly equivalent to what Action.apply does:

def read(id: Long) = Action.async {
    Future.successful(Ok(Json.toJson(User.read(id)))
}

User.read is still a blocking JDBC call, however, so this is no better than before.

Now let's say we're using an asynchronous DB call that looks something like this:

def read(id: Long): Future[User]

The controller function would look something like this:

def read(id: Long) = Action.async {
    User.read(id).map(user => Ok(Json.toJson(user)))
}

Think of it as more of a helper for using APIs that return Futures. The real benefits come from actual asynchronous implementations of those APIs. If you're stuck with blocking API (probably JDBC), there are other ways to manage that as well. This thread on the Play mailing list is a good read on the subject: https://groups.google.com/forum/#!topic/play-framework/WWQ0HeLDOjg



来源:https://stackoverflow.com/questions/23997418/are-there-any-benefits-in-using-non-async-actions-in-play-framework-2-2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!