A second Akka remote example: Sending objects as messages

A few days ago I shared the source code for a simple Akka remote actor example. In that example I showed how to communicate between actors in two different JVMs using Scala and Akka. In that example I showed how to communicate between the two JVMs using String messages because I didn’t want to make the example any harder than necessary.

Today, I’m taking that example just one step further to show how to communicate between actors on different JVMs by using custom objects for your messages.

Discussion

I’m not going to show all the details of the project layout this time. For all those details, see my first example. I’ll just show a few things.

First, the main project contains three subdirectories:

  1. Common
  2. HelloLocal
  3. HelloRemote

As before, the HelloRemote directory contains the source code for the “remote” system, and HelloLocal contains the source code for the “local” actor system.

The Common project

In this project the Common directory contains the source code for the classes that are shared between the local and remote systems. That code is in the src/main/scala/common/Common.scala file, and looks like this:

package common

case object Start
case class Message(msg: String)

The Start and Message objects will be used to send messages between the local and remote systems. To do this, run the sbt package command inside the Common directory. That command creates a JAR file named target/scala-2.10/common2.10-1.0.jar. Next, copy that JAR file to the lib_ folders in both the HelloLocal and HelloRemote projects.

The Remote project

The only thing new in the HelloRemote project compared to my first example is that it uses these objects rather than String instances to communicate with the HelloLocal project. The new code looks like this:

package remote

import akka.actor._
import common._

object HelloRemote extends App  {
  val system = ActorSystem("HelloRemoteSystem")
  val remoteActor = system.actorOf(Props[RemoteActor], name = "RemoteActor")
  remoteActor ! Message("The RemoteActor is alive")
}

class RemoteActor extends Actor {
  def receive = {
    case Message(msg) =>
        println(s"RemoteActor received message '$msg'")
        sender ! Message("Hello from the RemoteActor")
    case _ =>
        println("RemoteActor got something unexpected.")

  }
}

The Local project

Similarly, the only change to the HelloLocal project is that the code uses the custom objects as messages. The new code looks like this:

package local

import akka.actor._
import common._

object Local extends App {

  implicit val system = ActorSystem("LocalSystem")
  val localActor = system.actorOf(Props[LocalActor], name = "LocalActor")  // the local actor
  localActor ! Start                                                       // start the action

}

class LocalActor extends Actor {

  // create the remote actor
  val remote = context.actorFor("akka://HelloRemoteSystem@127.0.0.1:5150/user/RemoteActor")
  var counter = 0

  def receive = {
    case Start =>
        remote ! Message("Hello from the LocalActor")
    case Message(msg) =>
        println(s"LocalActor received message: '$msg'")
        if (counter < 5) {
            sender ! Message("Hello back to you")
            counter += 1
        }
    case _ =>
        println("LocalActor got something unexpected.")
  }

}

The code on Github

If you want to test and experiment with my code, you can clone my project from Github at this URL:

  • https://github.com/alvinj/AkkaRemoteObjectsAsMessages

Running the code

The steps to running the code in two JVMs is the same as before:

  1. cd into the HelloRemote directory.
  2. Type sbt run to start the remote actor system.
  3. In a separate terminal window, cd into the HelloLocal directory.
  4. Type sbt run to start the local actor system.

When the local actor system starts, it will send an initial message to the remote actor system. The remote actor will send a reply through its sender reference, and this will continue five times. When the action stops, stop each system by pressing Ctrl-C.

Problems

If you have any problems with this code, edit the application.conf file in the src/main/resources directory of the HelloLocal and HelloRemote projects, and remove the comments from the debug-related lines. That may help show

Summary

In summary, if you’re looking for an Akka remote example that uses custom objects for its messages, I hope you find this code useful. If there’s any secret sauce to this example, it’s knowing that you need to make your message classes available to both the local and remote JVMs. As the book, Akka Concurrency, states, the JVMs must both have copies of the classes, there is no way for each JVM to learn about the classes from each other.