About Adam Warski

Adam is one of the co-founders of SoftwareMill, a company specialising in delivering customised software solutions. He is also involved in open-source projects, as a founder, lead developer or contributor to: Hibernate Envers, a Hibernate core module, which provides entity versioning/auditing capabilities; ElasticMQ, an SQS-compatible messaging server written in Scala; Veripacks, a tool to specify and verify inter-package dependencies, and others.

Typed ask for Akka

Akka is a great tool for writing distributed applications. One thing that always surprised me though is that while being based on Scala, which is a very type-safe language, the elementary construct in Akka – an actor – is not really type safe. You can send any message to any actor, and get back any object in reply.

The upcoming 2.2 release of Akka will contain an experimental implementation of typed channels, which use macros to ensure type-safety in actor communication; but before that is final, here’s a simpler and less powerful approach, to add some typing to the ask pattern.

You can look at the ask pattern as a kind of asynchronous method invocation: you
 
send a message (its class corresponds to the method name) with some arguments, and expect a reply (method result). More specifically, we get back a Future, which will eventually hold the reply (if any). Note that the reply can also be of type Unit, corresponding to methods returning no result. Knowing when such “methods” complete may still be useful, though.

A very simple example of the basic ask pattern usage:

import akka.pattern.ask

case class LookupUser(id: Int)

// the actor impl should send back a message to the sender
val userFuture = actor ? LookupUser(10)

// userFuture: Future[Any]

userFuture onSuccess {
   case result => {
      // do something with the result
      // result has type Any 
   }
}

The not-so-nice thing here is that the return type of ? (see the AskSupport implementation) is Future[Any], as the actor may respond with any message. However ideally, when sending LookupUser we would want to get a Future[Option[User]], when sending UserCount a Future[Int] and so on.

This is in fact quite easy to implement. First of all, we must somehow embed the expected reply type in the message. For that we can use a trait, which takes the type of the expected response as a type parameter:

trait Replyable[T]

This can be used in the messages that we are sending to the actor:

case class LookupUser(id: Int) extends Replyable[Option[User]]
case class UserCount() extends Replyable[Int]

Now we need a variant of ? which returns a future with the right type parameter:

trait ReplySupport {
  implicit class ReplyActorRef(actorRef: ActorRef) {
    def ?[T](message: Replyable[T])
            (implicit timeout: Timeout, tag: ClassTag[T]): Future[T] = {
      akka.pattern.ask(actorRef, message).mapTo[T]
    }
  }
}

package object reply extends ReplySupport

You can see that we are simply re-using the existing ask implementation, and mapping the resulting future to the right type. The timeout is an implicit parameter of ask and ClassTag of mapTo, hence we must include them in the signature as well.

Usage is quite simple, in fact it’s almost the same as before, except for the import and that the future is of the right type:

import reply._

val userFuture = actor ? LookupUser(10)

// userFuture: Future[Option[User]]

userFuture onSuccess {
   case result => {
      // do something with the result
      // result has type Option[User] 
   }
}

That’s the actor-user side. What about the actor itself? How to ensure that if an actor receives a message of type Replyable[T], it will actually answer with T? As quite commonly in Scala, the answer again is a trait, which can be mixed into an actor:

trait ReplyingActor extends Actor {
  def receive = {
    case m: Replyable[_] if receiveReplyable.isDefinedAt(m) => {
      try {
        sender ! receiveReplyable(m)
      } catch {
        case e: Exception => sender ! Failure(e)
      }
    }
  }

  def receiveReplyable[T]: PartialFunction[Replyable[T], T]
}

And example usage:

class UserActor extends ReplyingActor {
   def receiveReplyable[T] = {
      case LookupUser(id) => Some(User(...))
      case UserCount() => 512
   }
}

Now this is all nicely type-checked. If we tried to return a String in the UserCount branch, we would get a compile-time error.
 

Reference: Typed ask for Akka from our JCG partner Adam Warski at the Blog of Adam Warski blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

2 Responses to "Typed ask for Akka"

Leave a Reply


six + 1 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close