As you may know, I’ve been working on building a fairly complex enterprise LOB application using Play, Scala, and Akka. When I started, I had a rudimentary understanding of Akka and Play, and I’d done some playing around with Akka before, but my experience was a far cry from the type of experience a grizzled, production-deployed veteran might have.

My website, without giving away any details, allows me to do a keyword search across multiple different types of entities. Let’s say I’ve built a zombie apocalypse preparedness social networking site (who doesn’t need one of those?!?) and I want to be able to enter a keyword and have it look through the repository containing identified zombie classifications as well as possible friends and even the names of weapons.

I built this in a way that I thought was pretty decent, I created a Search actor that takes a KeywordSearch case class message. This Search actor then asks the Akka actor system for references to the different repositories, which are also actors. In this case, I might need a reference to the ZombieIdentificationRepository actor, the WeaponRepository actor, and the UsersRepository actor.

This problem is screaming for parallelism. I want the search actor to send fire-and-sorta-forget messages to the different repositories and, when it gets answers from all three repositories, send a message back to the actor that invoked the search containing all of the results. Further, I want the web request itself to not block on waiting for the results, so I want to use Play’s asynchronous controller pattern.

When I first built the search, I had code that looked kind of like this:

def index(keyWord:String) = Action { implicit request =>
 ...
 val resFuture = ActorProvider.Searcher ? SearchActorProtocol.KeywordSearch(keyword)
 val results = Await.result(resFuture, timeout.duration).asInstanceOf[Array[SearchResult]]
 Ok(views.html.search.index(results)
}

So, while under the hood I was using an Actor, I’m still performing an explicit block. Worse, the search actor was also performing an explicit block as it was doing an Await.result for each of the different repository queries. I had heard that Future composition was possible, so I thought I’d give it a shot.

Here’s how I refactored the Search actor’s search method to combine multiple searches performed in parallel:

def performKeywordSearch(seeker: ActorRef, keyword: String) {
    implicit val timeout = Timeout(3 seconds)

    val zombieFuture = ActorProvider.ZombieRepository ? KeywordSearch(keyword)
    val weaponFuture = ActorProvider.WeaponRepository ? KeywordSearch(keyword)
    val userFuture = ActorProvider.UserRepository ? KeywordSearch(keyword)

    val combFuture = for {
        z <- zombieFuture.mapTo[Array[SearchResult]]
        w <- weaponFuture.mapTo[Array[SearchResult]]
        u <- userFuture.mapTo[Array[SearchResult]]
    } yield seeker ! ( z ++ w ++ u).sortBy( r => r.name )
}

Note that there isn’t a single line of blocking code in the preceding sample. Everything happens when it’s done and there’s no explicit “sit and wait” code. I can even then modify the search controller’s method to remove the Await.result:

...
val searchFuture = ActorProvider.Searcher ? SearchActorProtocol.KeywordSearch(keyword)
val timeoutFuture = play.api.libs.concurrent.Promise.timeout("Failed to finish search", 5 seconds)
Async {
    Future.firstCompletedOf(Seq(searchFuture, timeoutFuture)).map {
        case searchResults: Array[SearchResult] =>
            render {
                case Accepts.Html() => Ok(views.html.search.index(searchResults))
                case Accepts.Json() => Ok(Json.toJson(searchResults))
            }
        case t:String => InternalServerError(t)
    }
}

And now I’ve removed a chain of blocking calls and replaced all of it with completely asynchronous, non-blocking code and now the only thing that ever sits and waits is Play itself, as it awaits the response from the Actor.

Coding with Futures and in a completely asynchronous fashion with Actors is difficult, and it requires a lot of up front effort and takes time to understand what’s really going on, but, as you can see from the code above, the clean and simple non-blocking elegance that you get as a reward is well worth the effort.