RemoteActor in Scala

Concurrency in a whole bunch of languages is an error-prone affair, with shared memory and locks being complex mechanisms to get right. Too much locking, and you get deadlocked code; too little locking, and you trash another object’s data.

Erlang implements the concept of actors, which pass messages asynchronously between each other. An actor can be thought of as a thread in Java parlance. Any actor can send another actor a message, and each actor has a “mailbox” for incoming messages. Messages are discrete entities, not shared between the actors themselves, and the actors are totally decoupled from each other. Thus, rather than shared memory and locks, we have a “shared nothing” approach to concurrency.

At the moment, I’m building a simulator to mimic a network of nodes passing routing protocol packets between each other; using a programming model such as this just seems to Make Sense. This simulation may have to scale up quite a lot, so actually I want these actors to run on different machines. That’s slightly trickier, not because of the language model, but because of a slight lack of documentation for the relevant portion of the API in my chosen language, Scala.

Scala uses the same concurrency model as Erlang, but with the advantage that it’s newer, and is built upon Java (and thus has access to Java’s huge class library, so despite being a newer language it already has the power of a large, rigorously tested library behind it). It also offers the RemoteActor class, which helps mask the complexity of setting up TCP connections and constructing messages from the TCP bytestream; it allows a level of transparency between physical nodes when communicating with an actor which may (but does not have to be) located on a different physical machine.

So here’s my working RemoteActor code for a basic source/sink. This seems to work for me, and I spent quite a while trial-and-erroring to make it so. So, here’s the code.

My basicsource.scala:

package com.sds.testing

import scala.actors.Actor
import scala.actors.remote.RemoteActor
import scala.actors.remote.RemoteActor._
import scala.actors.remote.Node

object BasicSourceApp {
  def main(args: Array[String]) : Unit = {
    if (args.length == 2) {
      val remoteport = args(1).toInt
      val peer = Node(args(0), remoteport)
      val source = new RemoteSource(peer)
      source.start()
    }
    else {
      println("usage: scala BasicSourceApp [RemoteHostName] [RemotePort]")
    }
  }
}

class RemoteSource(peer: Node) extends Actor {
  def act() {
    RemoteActor.classLoader = getClass().getClassLoader()
    val sink = select(peer, 'SinkApp)
    link(sink)

    while (true) {
      sink ! "Hello, world!"
      Thread sleep 5000
    }
  }
}

In this, the link() call isn’t actually used, but it can be used to inform this actor that the remote actor has terminated. The application is called, which creates a new RemoteSource with the specified hostname and port number. select() looks up “SinkApp” on the remote peer and creates whatever local proxies it needs. You can then send messages to “sink” using the “!” operator as you would a local actor.

And, here’s my basicsink.scala

package com.sds.testing

import scala.actors.Actor
import scala.actors.Actor._
import scala.actors.remote.RemoteActor
import scala.actors.remote.RemoteActor._

object BasicSinkApp {
  def main(args: Array[String]) : Unit = {
    if (args.length == 1) {
      val port = args(0).toInt
      val sink = new RemoteSink(port)
      sink.start()
    }
    else {
      println("usage: scala BasicSinkApp [LocalPort]")
    }
  }
}

class RemoteSink(port: Int) extends Actor {
  RemoteActor.classLoader = getClass().getClassLoader()
  def act() {
    alive(port)
    register('SinkApp, self)

    while (true) {
      receive {
        case msg =>
          println(msg)
      }
    }
  }
}

Here, alive() creates a socket and binds to it using the specified port, and register maps “SinkApp” to this actor, such that the select() call from the source can succeed. Afterward, all the sink does is repeatedly check its own mailbox, and prints out whatever messages it’s received. These few calls make for very little boilerplate around Scala’s standard message passing code.

The code for this post was heavily borrowed fromthe simple code posted at dirkmeister.blogspot.com, but it took me a while to make even that work, so I figured some even-more-simplistic tutorial code might be useful.

Footnote

Posted by Stephen Strowes on Wednesday, April 1st, 2009. You can follow me on twitter.

Recent Posts

(full archive)

All content, including images, © Stephen D. Strowes, 2000–2016. Hosted by Digital Ocean.