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:
- Common
- HelloLocal
- 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:
cd
into the HelloRemote directory.- Type
sbt run
to start the remote actor system. - In a separate terminal window,
cd
into the HelloLocal directory. - 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.