Protected

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.
Here is how to start up the RemoteNode and specify the hostname and port programatically:
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):
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.
You can create more than one RemoteServer. Just instantiate it with ‘new’ and make sure that the port is unique.
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.
You simply need to make sure that the service is turned on in the external ‘akka.conf’ configuration file.
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:
You can also create remote actor using lightweight anonymous syntax.
Here is an example:
Actors can also be made remote after instantiation by invoking one of the ‘makeRemote’ methods.
Here is an example:
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.
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:
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:
or the alternative:
This means that you can, if you find it useful, specify another reply-to address for the remote receiving actor to use when replying.
You can define the Active Object to be a remote service by adding the ‘RemoteAddress’ configuration element in the declarative supervisor configuration:
You can also define an Active Object to be remote programmatically when creating it explicitly:
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.
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:
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.
The Remote Client automatically performs reconnection upon connection failure.
You can configure it like this:
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>
