Akka and Scalatra

On my current project, I’ve been using Akka to handle the Service Layer of my application while using Scalatra for my REST controllers.  This combination works quite well, though it took me a little bit of time to figure out how to integrate Scalatra and Akka.  The examples presented on the Scalatra website didn’t exactly work for me (it’s possible they’ve since been fixed).  But after some studying of the Akka and Scalatra API documentation and some good ol’ fashion trial-and-error, I got to something that worked.  First, Akka actors are set up and initialized in ScalatraBootstrap.scala thusly:

class ScalatraBootstrap extends LifeCycle with DatabaseInit {
  //initialize the Actor System
  val system = ActorSystem(actorSystemName)
  //initialize Service Actors
  val userServiceActor = system.actorOf(Props[UserServiceActor].withRouter(
    SmallestMailboxRouter(nrOfInstances = 10)), "userRouter")

  override def init(context: ServletContext) {

    //mount REST controllers
    context.mount(new UsersController(system, userServiceActor), usersPath)

  }

  override def destroy(context: ServletContext) {
    system.shutdown() // shut down the actor system
  }
}

I’m initializing each actor with a router (in this case, a SmallestMailboxRouter, though others, such as a RoundRobinRouter are also available).  The router will create up to 10 child actors and route incoming messages to the actor with the least number of ‘messages’ in its inbox.

The Scalatra controller responds to a request for a resource by sending a message to the appropriate actor (I’m using one Actor type per resource) using a Future and returning the result.  Scalatra provides an AsyncResult construct that helps here:

  /** Get a specific user's information
    * User-id specified by id
    */
  get("/:id", operation(getUser)){
    basicAuthWithCustomerCheck() match {
      case None => //do nothing
      case Some(user) =>
        new AsyncResult{
          val is: Future[_] =
            ask(userServiceActor, new GetUserByIdMessage(user,
              params("id").toLong))(timeout.toMillis).
              mapTo[Either[(Int, String), UserDto]] map {
              case Right(userDto) => userDto
              case Left((errorCode, msg)) => response.sendError(errorCode, msg)
            }
        }
    }
  }

My actor here happens to return an ‘Either’ type in response to a request.  By convention, a ‘Left’ response indicates an error condition (in this case a tuple containing the HTTP error code to return and a message), and a ‘Right’ response indicates success and contains the requested data (a ‘User’ object). The actor itself looks like this:

case class GetUserByIdMessage(user: User, id: Long)

class UserServiceActor extends Actor{

  def receive = {
    case getUserByIdMessage: GetUserByIdMessage =>
      sender ! handleGetUserByIdMessage(getUserByIdMessage)
  }

  def handleGetUserByIdMessage(getUserByIdMessage: GetUserByIdMessage):
  Either[(Int, String), UserDto] = {
    //Process request.  Return an (error code, message) tuple on failure, and the
    //data on success  
  }
}

The message types are implemented as case classes, and enter the actor in the ‘receive’ method, which passes each message to a handler and returns the result to the message’s ‘sender’ (the controller).

One thought on “Akka and Scalatra

  1. Thanks so much James, your post enabled me to achieve concurrent processing of requests using Scalatra. The “click” was on the use of the router, which makes more than one actor available for processing at the same time.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s