Reviewed and improved remote-actors doc
This commit is contained in:
parent
888af3479e
commit
1c29885f3d
4 changed files with 268 additions and 247 deletions
|
|
@ -1,6 +1,10 @@
|
|||
Remote Actors (Scala)
|
||||
=====================
|
||||
|
||||
.. sidebar:: Contents
|
||||
|
||||
.. contents:: :local:
|
||||
|
||||
Module stability: **SOLID**
|
||||
|
||||
Akka supports starting and interacting with Actors and Typed Actors on remote nodes using a very efficient and scalable NIO implementation built upon `JBoss Netty <http://jboss.org/netty>`_ and `Google Protocol Buffers <http://code.google.com/p/protobuf/>`_ .
|
||||
|
|
@ -74,6 +78,7 @@ Normally you should not have to start and stop the client connection explicitly
|
|||
.. code-block:: scala
|
||||
|
||||
import akka.actor.Actor._
|
||||
import java.net.InetSocketAddress
|
||||
|
||||
remote.shutdownClientConnection(new InetSocketAddress("localhost", 6666)) //Returns true if successful, false otherwise
|
||||
remote.restartClientConnection(new InetSocketAddress("localhost", 6666)) //Returns true if successful, false otherwise
|
||||
|
|
@ -143,12 +148,6 @@ The default behavior is that the remote client will maintain a transaction log o
|
|||
|
||||
If you choose a capacity higher than 0, then a bounded queue will be used and if the limit of the queue is reached then a 'RemoteClientMessageBufferException' will be thrown.
|
||||
|
||||
You can also get an Array with all the messages that the remote client has failed to send. Since the remote client events passes you an instance of the RemoteClient you have an easy way to act upon failure and do something with these messages (while waiting for them to be retried).
|
||||
|
||||
.. code-block:: scala
|
||||
|
||||
val pending: Array[Any] = Actor.remote.pendingMessages
|
||||
|
||||
Running Remote Server in untrusted mode
|
||||
---------------------------------------
|
||||
|
||||
|
|
@ -255,24 +254,16 @@ You can also generate the secure cookie by using the 'Crypt' object and its 'gen
|
|||
|
||||
The secure cookie is a cryptographically secure randomly generated byte array turned into a SHA-1 hash.
|
||||
|
||||
Remote Actors
|
||||
-------------
|
||||
|
||||
Akka has two types of remote actors:
|
||||
|
||||
* Client-initiated and managed. Here it is the client that creates the remote actor and "moves it" to the server.
|
||||
* Server-initiated and managed. Here it is the server that creates the remote actor and the client can ask for a handle to this actor.
|
||||
|
||||
They are good for different use-cases. The client-initiated are great when you want to monitor an actor on another node since it allows you to link to it and supervise it using the regular supervision semantics. They also make RPC completely transparent. The server-initiated, on the other hand, are great when you have a service running on the server that you want clients to connect to, and you want full control over the actor on the server side for security reasons etc.
|
||||
|
||||
Client-managed Remote Actors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
----------------------------
|
||||
|
||||
DEPRECATED AS OF 1.1
|
||||
|
||||
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.
|
||||
The client creates the remote actor and "moves it" to the server.
|
||||
|
||||
Actors can be made remote by calling remote().actorOf[MyActor](host, port)
|
||||
When you define an actor 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 by calling remote.actorOf[MyActor](host, port)
|
||||
|
||||
Here is an example:
|
||||
|
||||
|
|
@ -280,29 +271,30 @@ Here is an example:
|
|||
|
||||
import akka.actor.Actor
|
||||
|
||||
class MyActor extends RemoteActor() {
|
||||
class MyActor extends Actor {
|
||||
def receive = {
|
||||
case "hello" => self.reply("world")
|
||||
}
|
||||
}
|
||||
|
||||
val remote = Actor.remote().actorOf[MyActor]("192.68.23.769", 2552)
|
||||
val remoteActor = Actor.remote.actorOf[MyActor]("192.68.23.769", 2552)
|
||||
|
||||
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.
|
||||
|
||||
.. code-block:: scala
|
||||
|
||||
...
|
||||
spawnRemote[MyActor](hostname, port)
|
||||
spawnLinkRemote[MyActor](hostname, port)
|
||||
self.spawnRemote[MyActor](hostname, port, timeout)
|
||||
self.spawnLinkRemote[MyActor](hostname, port, timeout)
|
||||
...
|
||||
|
||||
Server-managed Remote Actors
|
||||
----------------------------
|
||||
|
||||
Here it is the server that creates the remote actor and the client can ask for a handle to this actor.
|
||||
|
||||
Server side setup
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
The API for server managed remote actors is really simple. 2 methods only:
|
||||
|
||||
.. code-block:: scala
|
||||
|
|
@ -358,10 +350,10 @@ There are many variations on the 'remote#actorFor' method. Here are some of them
|
|||
|
||||
.. code-block:: scala
|
||||
|
||||
... = actorFor(className, hostname, port)
|
||||
... = actorFor(className, timeout, hostname, port)
|
||||
... = actorFor(uuid, className, hostname, port)
|
||||
... = actorFor(uuid, className, timeout, hostname, port)
|
||||
... = remote.actorFor(className, hostname, port)
|
||||
... = remote.actorFor(className, timeout, hostname, port)
|
||||
... = remote.actorFor(uuid, className, hostname, port)
|
||||
... = remote.actorFor(uuid, className, timeout, hostname, port)
|
||||
... // etc
|
||||
|
||||
All of these also have variations where you can pass in an explicit 'ClassLoader' which can be used when deserializing messages sent from the remote actor.
|
||||
|
|
@ -371,11 +363,16 @@ Running sample
|
|||
|
||||
Here is a complete running sample (also available `here <http://github.com/jboner/akka/blob/master/akka-core/src/test/scala/ServerInitiatedRemoteActorSample.scala>`_):
|
||||
|
||||
Paste in the code below into two sbt concole shells. Then run:
|
||||
|
||||
- ServerInitiatedRemoteActorServer.run() in one shell
|
||||
- ServerInitiatedRemoteActorClient.run() in the other shell
|
||||
|
||||
.. code-block:: scala
|
||||
|
||||
import akka.actor.Actor
|
||||
import akka.util.Logging
|
||||
import Actor._
|
||||
import akka.event.EventHandler
|
||||
|
||||
class HelloWorldActor extends Actor {
|
||||
def receive = {
|
||||
|
|
@ -385,27 +382,27 @@ Here is a complete running sample (also available `here <http://github.com/jbone
|
|||
|
||||
object ServerInitiatedRemoteActorServer {
|
||||
|
||||
def run = {
|
||||
def run() {
|
||||
remote.start("localhost", 2552)
|
||||
remote.register("hello-service", actorOf[HelloWorldActor])
|
||||
}
|
||||
|
||||
def main(args: Array[String]) = run
|
||||
def main(args: Array[String]) { run() }
|
||||
}
|
||||
|
||||
object ServerInitiatedRemoteActorClient extends Logging {
|
||||
object ServerInitiatedRemoteActorClient {
|
||||
|
||||
def run = {
|
||||
def run() {
|
||||
val actor = remote.actorFor("hello-service", "localhost", 2552)
|
||||
val result = actor !! "Hello"
|
||||
log.info("Result from Remote Actor: %s", result)
|
||||
EventHandler.info("Result from Remote Actor: %s", result)
|
||||
}
|
||||
|
||||
def main(args: Array[String]) = run
|
||||
def main(args: Array[String]) { run() }
|
||||
}
|
||||
|
||||
Automatic remote 'sender' reference management
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
----------------------------------------------
|
||||
|
||||
The sender of a remote message will be reachable with a reply through the remote server on the node that the actor is residing, automatically.
|
||||
Please note that firewalled clients won't work right now. [2011-01-05]
|
||||
|
|
@ -419,10 +416,10 @@ Here is an example of overriding the 'id' field:
|
|||
|
||||
.. code-block:: scala
|
||||
|
||||
import akka.util.UUID
|
||||
import akka.actor.newUuid
|
||||
|
||||
class MyActor extends Actor {
|
||||
self.id = UUID.newUuid.toString
|
||||
self.id = newUuid.toString
|
||||
def receive = {
|
||||
case "hello" => self.reply("world")
|
||||
}
|
||||
|
|
@ -430,11 +427,9 @@ Here is an example of overriding the 'id' field:
|
|||
|
||||
val actor = remote.actorOf[MyActor]("192.68.23.769", 2552)
|
||||
|
||||
Remote Typed Actors
|
||||
-------------------
|
||||
|
||||
Client-managed Remote Actors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Client-managed Remote Typed Actors
|
||||
----------------------------------
|
||||
|
||||
DEPRECATED AS OF 1.1
|
||||
|
||||
|
|
@ -458,13 +453,13 @@ You can also define an Typed Actor to be remote programmatically when creating i
|
|||
|
||||
... // use pojo as usual
|
||||
|
||||
Server-managed Remote Actors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Server-managed Remote Typed Actors
|
||||
----------------------------------
|
||||
|
||||
WARNING: Remote TypedActors do not work with overloaded methods on your TypedActor, refrain from using overloading.
|
||||
|
||||
Server side setup
|
||||
*****************
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
The API for server managed remote typed actors is nearly the same as for untyped actor
|
||||
|
||||
|
|
@ -507,20 +502,20 @@ They are also useful if you need to perform some cleanup when a client disconnec
|
|||
Note that the second argument in registerTypedPerSessionActor is an implicit function. It will be called to create an actor every time a session is established.
|
||||
|
||||
Client side usage
|
||||
*****************
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: scala
|
||||
|
||||
val actor = remote.typedActorFor(classOf[RegistrationService], "user-service", 5000L, "localhost", 2552)
|
||||
actor.registerUser(…)
|
||||
|
||||
There are variations on the 'RemoteClient#typedActorFor' method. Here are some of them:
|
||||
There are variations on the 'remote#typedActorFor' method. Here are some of them:
|
||||
|
||||
.. code-block:: scala
|
||||
|
||||
... = typedActorFor(interfaceClazz, serviceIdOrClassName, hostname, port)
|
||||
... = typedActorFor(interfaceClazz, serviceIdOrClassName, timeout, hostname, port)
|
||||
... = typedActorFor(interfaceClazz, serviceIdOrClassName, timeout, hostname, port, classLoader)
|
||||
... = remote.typedActorFor(interfaceClazz, serviceIdOrClassName, hostname, port)
|
||||
... = remote.typedActorFor(interfaceClazz, serviceIdOrClassName, timeout, hostname, port)
|
||||
... = remote.typedActorFor(interfaceClazz, serviceIdOrClassName, timeout, hostname, port, classLoader)
|
||||
|
||||
Data Compression Configuration
|
||||
------------------------------
|
||||
|
|
@ -583,15 +578,19 @@ So a simple listener actor can look like this:
|
|||
|
||||
.. code-block:: scala
|
||||
|
||||
import akka.actor.Actor
|
||||
import akka.actor.Actor._
|
||||
import akka.remoteinterface._
|
||||
|
||||
val listener = actorOf(new Actor {
|
||||
def receive = {
|
||||
case RemoteClientError(cause, client, address) => ... // act upon error
|
||||
case RemoteClientDisconnected(client, address) => ... // act upon disconnection
|
||||
case RemoteClientConnected(client, address) => ... // act upon connection
|
||||
case RemoteClientStarted(client, address) => ... // act upon client shutdown
|
||||
case RemoteClientShutdown(client, address) => ... // act upon client shutdown
|
||||
case RemoteClientWriteFailed(request, cause, client, address) => ... // act upon write failure
|
||||
case _ => //ignore other
|
||||
case RemoteClientError(cause, client, address) => //... act upon error
|
||||
case RemoteClientDisconnected(client, address) => //... act upon disconnection
|
||||
case RemoteClientConnected(client, address) => //... act upon connection
|
||||
case RemoteClientStarted(client, address) => //... act upon client shutdown
|
||||
case RemoteClientShutdown(client, address) => //... act upon client shutdown
|
||||
case RemoteClientWriteFailed(request, cause, client, address) => //... act upon write failure
|
||||
case _ => // ignore other
|
||||
}
|
||||
}).start()
|
||||
|
||||
|
|
@ -637,15 +636,19 @@ So a simple listener actor can look like this:
|
|||
|
||||
.. code-block:: scala
|
||||
|
||||
import akka.actor.Actor
|
||||
import akka.actor.Actor._
|
||||
import akka.remoteinterface._
|
||||
|
||||
val listener = actorOf(new Actor {
|
||||
def receive = {
|
||||
case RemoteServerStarted(server) => ... // act upon server start
|
||||
case RemoteServerShutdown(server) => ... // act upon server shutdown
|
||||
case RemoteServerError(cause, server) => ... // act upon server error
|
||||
case RemoteServerClientConnected(server, clientAddress) => ... // act upon client connection
|
||||
case RemoteServerClientDisconnected(server, clientAddress) => ... // act upon client disconnection
|
||||
case RemoteServerClientClosed(server, clientAddress) => ... // act upon client connection close
|
||||
case RemoteServerWriteFailed(request, cause, server, clientAddress) => ... // act upon server write failure
|
||||
case RemoteServerStarted(server) => //... act upon server start
|
||||
case RemoteServerShutdown(server) => //... act upon server shutdown
|
||||
case RemoteServerError(cause, server) => //... act upon server error
|
||||
case RemoteServerClientConnected(server, clientAddress) => //... act upon client connection
|
||||
case RemoteServerClientDisconnected(server, clientAddress) => //... act upon client disconnection
|
||||
case RemoteServerClientClosed(server, clientAddress) => //... act upon client connection close
|
||||
case RemoteServerWriteFailed(request, cause, server, clientAddress) => //... act upon server write failure
|
||||
}
|
||||
}).start()
|
||||
|
||||
|
|
@ -662,7 +665,7 @@ 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 '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 <serialization>`_.
|
||||
Here are some examples, but full documentation can be found in the :ref:`serialization-scala`.
|
||||
|
||||
Scala JSON
|
||||
^^^^^^^^^^
|
||||
|
|
@ -676,7 +679,7 @@ Protobuf
|
|||
|
||||
Protobuf message specification needs to be compiled with 'protoc' compiler.
|
||||
|
||||
.. code-block:: scala
|
||||
::
|
||||
|
||||
message ProtobufPOJO {
|
||||
required uint64 id = 1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue