[2.2 Scala] Play 2.2 async migration difficulties...

583 views
Skip to first unread message

Mike Bryant

unread,
Oct 9, 2013, 1:41:51 PM10/9/13
to play-fr...@googlegroups.com
Anyone else finding the migration to 2.2 a real challenge?  I'm using an async (webservice) DB and I seem to have depended a lot of the ability of AsyncResult to unravel a set of nested futures "automatically", and now I puzzling over how I'm going to do this with the new Result structure.

One thing I've been doing with 2.1 a fair bit - wisely or not - is using helper closures like this:

def withSomethingFromDb(f: Something => Result) = Async {
 
MyDb.getSomething.map(f)
}

and then using those when, say, re-displaying a form on a post request after a binding failure:

def saveItPost = Action { implicit request =>

  myForm
.bindFromRequest.fold(
    err
=> withSomethingFromDb { thing =>
     
BadRequest(myview(err, thing))
   
},
    item
=> Redirect("/").flashing("ok!")
 
)
}




This is a simple example (and easily fixed by using Action.async and wrapping the redirect in a pure future) but the point is you previously didn't have to care whether you were running in a deferred context or not. This was very handy in more complex situations.

Since I haven't seen many posts agonising over this I'm wondering if a) not many people have yet migrated an app with this kind of async use/abuse, or b) there are simple solutions to avoiding Future.flatMap hell.

Christian Papauschek

unread,
Oct 9, 2013, 3:49:24 PM10/9/13
to play-fr...@googlegroups.com
It seems your working with a database driven app. If, like ours, your database driver is blocking anyway, then you could create your own Action builder which always runs in a deferred context. This has the advantage of running database access code in a thread pool that you can configure as needed.

object MyAction {
    def apply[A](parser: BodyParser[A])(f: Request[A] => SimpleResult) : Action[A] = Action.async(parser)(request => Future(f(request)))
}

Now you dont have to deal with futures anymore (you dont have a real performance advantage from them anyway, if DB access is blocking)

Mike Bryant

unread,
Oct 9, 2013, 4:38:52 PM10/9/13
to play-fr...@googlegroups.com
Hi Christian,

I have some cases where I'm accessing a blocking DB (user account info), but most of my data is coming from a REST service accessed via WS in a non-blocking manner. Hitherto it's been quite easy to compose actions that fetch various bits of data without worrying if the eventual Result is deferred or not.

I suspect a lot more time getting to know the new Action/ActionBuilder stuff is in order...

Guillaume Bort

unread,
Oct 9, 2013, 4:39:16 PM10/9/13
to play-fr...@googlegroups.com
Right, but don't forget to manage on which execution context will be run the user code handled by this Action builder:

You can specify it explicitly when calling the future:

Future(f(request))(blockingCodeExecutionContext)

So you can create and configure appropriately this blockingCodeExecutionContext


--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--

Christian Papauschek

unread,
Oct 10, 2013, 4:33:10 AM10/10/13
to play-fr...@googlegroups.com
When using non-blocking calls, like the ones from the Play web services api, there seems to be no way around the Action.async builder...

Can anyone from the dev team confirm this?

Guillaume Bort

unread,
Oct 10, 2013, 4:52:01 AM10/10/13
to play-fr...@googlegroups.com
When using non-blocking calls, like the ones from the Play web services api, there seems to be no way around the Action.async builder...

Not sure what you mean.

If an async event occurs once in your action flow, then the result must be a Future[SimpleResult], even if some results are computed directly. But you can transform any result into a pure successful async result using something like `Future.successful(BadRequest("some errors..."))`.

Christian Papauschek

unread,
Oct 10, 2013, 5:06:12 AM10/10/13
to play-fr...@googlegroups.com
I'm just interested in an answer to the original question by Mike.

Lets say you have an Action that sometimes returns synchronous SimpleResult, and sometimes Future[SimpleResult].

In Play 2.2 you could just use a normal Action and use the Async+AsyncResult helper whenever needed.
In Play 2.3, you have to always use Action.async, which means you need to "decorate" all the synchronous results with Future.successful.

Or is there another way to mix Future and non-future results in Play 2.3, except the deprecated ones?

Marius Soutier

unread,
Oct 10, 2013, 4:55:01 PM10/10/13
to play-fr...@googlegroups.com
Yes, that's true. It was discussed on the mailing list, but the choice had already been made.

You can take your sometimes-async-Action, wrap the essentials in an ActionBuilder (let's call it MyAction), and define two different Actions in your controller with MyAction and MyAction.async.
Message has been deleted

Mike Bryant

unread,
Oct 11, 2013, 7:51:40 PM10/11/13
to play-fr...@googlegroups.com
Okay, having spent some time fiddling about with a toy Play 2.2 project, and studying Marius's excellent blog post and accompanying code I feel a bit more availed of the general situation, but I'm still finding the ins and outs of how I'm going to migrate my code difficult to grasp. My particular situation is complicated by the fact that I'm using play-2-auth, which uses a different way of doing action composition.

Bottom line seems to be, as far as I can tell:
 - Play 2.0/2.1 made it very easy to use asynchronous, non-blocking operations without worrying about many "futures" you'd eventually end up in, since AsyncResult would just handle it "magically"
 - this is no longer the case
 - ActionBuilder gives you the flexibility to do async/synchronous stuff depending on context, but is difficult to compose (and, frankly, a confusing API, IMHO)
 - the alternative might be to write lots of duplicate async/synchronous versions of plain Actions if you want to compose stuff flexibly

I totally understand why these changes have been made and how the simplified result structure makes it easier to do a lot of useful stuff more easily, but I can't help but feel that one of Play 2's big selling points - working with async stuff is easy! - has backtracked a lot. Then again my understanding is still really limited, and since not many other people have raised objections I must be in quite a small minority here.

Sorry to be gripey - I really do appreciate the fine work the Play devs are doing.
~Mike

Mike Bryant

unread,
Oct 13, 2013, 7:52:38 PM10/13/13
to play-fr...@googlegroups.com
I've created an issue about this here.
Reply all
Reply to author
Forward
0 new messages