I want to make two calls to my database which will take a while to return a result, and I don’t want to block the current thread. I have used Akka Futures to wrap the database calls.
Instead of waiting (blocking) for both calls to return, I would like to specify a callback function to be called, which can then render the response. How do I do that? Here is my controller code:
def showPie = IsAuthenticated(Roles.validator) { user => implicit request =>
val eventUid = request.session.get(EventUid).get
val printed = Akka.future(TicketRepository.getCountForState(eventUid, "Printed"))
val validated = Akka.future(TicketRepository.getCountForState(eventUid, "Validated"))
//this would be evil, because it would block: Ok(views.html.pie(printed.await(1000).get, validated.await(1000).get))
//create a promise for all the promised results
val promise = Promise.sequence(List(printed, validated))
//this doesnt work, but how can I make it work WITHOUT blocking this thread?
promise.callWhenResultIsReady(Ok(view.html.pie(promise.get))
}
You’re close. You can simple call
mapon a promise to deal with it. Inside an Async block, it stays nonblocking. Relevant documentation (see “AsyncResult”).edit:
From your comment below, let’s take a closer look at the Async block.
Asynctakes aPromise, and returns anAsyncResult, which is a subtype ofResult(which is whatActionneeds).Since the
mapfunction is called whenpromiseis complete, this stays non-blocking. This whole block returns quickly with anAsyncResult, and Play! manages it in a similar fashion by returning to the client when it finishes (and freeing Play! to do other things in the meantime).