Play 2.0 Scala and async callbacks

playframework-2.0, scala

Solution

You're close. You can simple call `map` on a promise to deal with it. Inside an Async block, it stays nonblocking. Relevant documentation (see "AsyncResult").

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"))

    //create a promise for all the promised results
    val promise = Promise.sequence(List(printed, validated))
    Async {
        promise map { res =>
            Ok("Got it!" + res)
        }
    }
}

edit: From your comment below, let's take a closer look at the Async block. `Async` takes a `Promise`, and returns an `AsyncResult`, which is a subtype of `Result` (which is what `Action` needs).

    Async {
        // We take the promise, and add something akin to a callback
        //  function with `map`. This new function is called when `promise`
        //  is complete.
        val result = promise map { res => // this is the redeemed promise
          Ok("Got it!" + res)
        }
        result // this is the new promise
    } 

Since the `map` function is called when `promise` is complete, this stays non-blocking. This whole block returns quickly with an `AsyncResult`, 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).

Problem

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)) } ```

Original source