Protected
Protected

Remote Actors and Active Objects


Akka supports starting Actors and Active Objects on remote nodes using a very efficient NIO implementation built upon JBoss Netty and Google Protocol Buffers .

The usage is completely transparent both in regards to sending messages and error handling and propagation as well as supervision, linking and restarts. You can send references to other Actors as part of the message.

Starting up the remote service


Starting remote service in user code as a library


Here is how to start up the RemoteNode and specify the hostname and port programatically:
import se.scalablesolutions.akka.remote.RemoteNode
 
RemoteNode.start("localhost", 9999)
 
// Specify the classloader to use to load the remote class (actor or active object)
RemoteNode.start("localhost", 9999, classLoader)

Here is how to start up the RemoteNode and specify the hostname and port in the ‘akka.conf’ configuration file (see the section below for details):
import se.scalablesolutions.akka.remote.RemoteNode
 
RemoteNode.start
 
// Specify the classloader to use to load the remote class (actor or active object)
RemoteNode.start(classLoader)

When you start up a 'RemoteNode' then the node is always automatically joining the Akka cluster. If you don't want that then you have to create a 'RemoteServer' intstance and pass in 'false' into the constructor. See below.

Start up more than one remote server


You can create more than one RemoteServer. Just instantiate it with ‘new’ and make sure that the port is unique.
import se.scalablesolutions.akka.remote.RemoteServer
 
val myServer = new RemoteServer
myServer.start("localhost", 9991)
 
val yourServer = new RemoteServer
yourServer.start("localhost", 9992)

If you pass in 'false' into the constructor of the 'RemoteServer' then the server does not join the Akka cluster. Default is that it does join the cluster.

Starting remote service as part of the stand-alone Kernel


You simply need to make sure that the service is turned on in the external ‘akka.conf’ configuration file.
<remote>
  <server>
    service = on
    hostname = "localhost"
    port = 9999
    connection-timeout = 1000 # in millis
  </server>
</remote>

Remote Actors


When you define an actors as being remote it is instantiated as on the remote host and your local actor becomes a proxy, it works as a handle to the remote actor. The real execution is always happening on the remote node.

Actors can be made remote declaratively by extending the 'RemoteActor(hostname: String, port: Int)' abstract class.

Here is an example:
class MyActor extends RemoteActor("192.68.23.769", 9999) {
  def receive = {
    case fun => reply(fun())
  }
}

You can also create remote actor using lightweight anonymous syntax.
Here is an example:
val remoteActor = actor("192.68.23.769", 9999) {
  case fun => reply(fun())
}

Actors can also be made remote after instantiation by invoking one of the ‘makeRemote’ methods.
def makeRemote(hostname: String, port: Int)
 
def makeRemote(address: InetSocketAddress)

Here is an example:
class MyActor extends Actor {
  makeRemote("192.68.23.769", 9999)
 
  def receive = {
    case fun => reply(fun())
  }
}

An Actor can also start remote child Actors through one of the “spawn/link” methods. These will start, link and make the Actor remote atomically.
...
startLinkRemote(actor, hostname, port)
spawnRemote(classOf[MyActor], hostname, port)
spawnLinkRemote(classOf[MyActor], hostname, port)
...

Identifying remote actors


The 'id' field in the 'Actor' class is of importance since it is used as identifier for the remote actor. If you want to create a brand new actor every time you instantiate a remote actor then you have to set the 'id' field to a unique 'String' for each instance. If you want to reuse the same remote actor instance for each new remote actor (of the same class) you create then you don't have to do anything since the 'id' field by default is equal to the name of the actor class.

Here is an example of overriding the 'id' field:

import se.scalablesolutions.akka.util.UUID
 
class MyActor extends RemoteActor("192.68.23.769", 9999) {
  id = UUID.newUuid.toString
  def receive = {
    case fun => reply(fun())
  }
}

Support for replying to remote actors


When using actors locally, an implicit sender reference is passed on along with the message. This makes it possible to either use ‘reply’ to respond to the sending actor or to use the 'sender' member field reference in the receiving actor. This also works with remote actors when a contact address is available at the sender. If a hostname and port is specified in ‘akka.conf’ as described in the previous section, it is used automatically as contact address. The contact address can also be set explicitly using:
setContactAddress(hostname: String, port: Int)

or the alternative:
setContactAddress(address: InetSocketAddress)

This means that you can, if you find it useful, specify another reply-to address for the remote receiving actor to use when replying.

Remote Active Objects


You can define the Active Object to be a remote service by adding the ‘RemoteAddress’ configuration element in the declarative supervisor configuration:
new Component(
  Foo.class,
  new LifeCycle(new Permanent(), 1000),
  1000,
  new RemoteAddress("localhost", 9999))

You can also define an Active Object to be remote programmatically when creating it explicitly:
ActiveObjectFactory factory = new ActiveObjectFactory();
 
POJO pojo = factory.newRemoteInstance(POJO.class, 1000, "localhost", 9999)
 
... // use pojo as usual

Message Serialization


All messages that are sent to remote actors needs to be serialized to binary format to be able to travel over the wire to the remote node. This is done by letting your messages extend one of the traits in the 'se.scalablesolutions.akka.serialization.Serializable' object. If the messages don't implement any specific serialization trait then the runtime will try to use standard Java serialization.

Here are some examples, but full documentation can be found in the Serialization section.

Scala JSON

case class MyMessage(id: String, value: Tuple2[String, Int]) extends Serializable.ScalaJSON

Protobuf

import com.google.protobuf.Message
case class User(username: String, password: String, email: String) extends Serializable.Protobuf[User] {
  def getMessage: Message = ... // Return the Protobuf generated Message class
}

SBinary

case class User(firstNameLastName: Tuple2[String, String], email: String, age: Int) extends Serializable.SBinary[User] {
  import sbinary.DefaultProtocol._
 
  def this() = this(null, null, 0)
 
  implicit object UserFormat extends Format[User] {
    def reads(in : Input) = User(
      read[Tuple2[String, String]](in),
      read[String](in),
      read[Int](in))
    def writes(out: Output, value: User) = {
      write[Tuple2[String, String]](out, value. firstNameLastName)
      write[String](out, value.email)
      write[Int](out, value.age)
    }
  }
 
  def fromBytes(bytes: Array[Byte]) = fromByteArray[User](bytes)
 
  def toBytes: Array[Byte] = toByteArray(this)
}

Data Compression Configuration


Akka uses compression to minimize the size of the data sent over the wire. Currently it only supports 'zlib' compression but more will come later.

You can configure it like this:
<remote>
  compression-scheme = "zlib" # Options: "zlib" (lzf to come), leave out for no compression
  zlib-compression-level = 6  # Options: 0-9 (1 being fastest and 9 being the most compressed), default is 6
 
  ...
</remote>

Code provisioning


Akka does currently not support automatic code provisioning but requires you to have the remote actor class files available on both the "client" the "server" nodes.
This is something that will be addressed soon. Until then, sorry for the inconvenience.


Remote Client Reconnect Configuration


The Remote Client automatically performs reconnection upon connection failure.

You can configure it like this:
<remote>
  <client>
    reconnect-delay = 5000    # in millis (5 sec default)
    read-timeout = 10000      # in millis (10 sec default)
  <client>
</remote>

Optional: comment for page history


Looking for tags?

  Cancel
Home
close
Loading...
Home Turn Off "Getting Started"
close
Loading...