remote deploy docs & provider.getExternalAddressFor (see #1765)

This commit is contained in:
Roland 2012-02-02 09:40:17 +01:00
parent 10974acfe8
commit 76bba1f530
10 changed files with 217 additions and 29 deletions

View file

@ -134,6 +134,14 @@ trait ActorRefProvider {
* is usually initiated by stopping the guardian via ActorSystem.stop().
*/
def terminationFuture: Future[Unit]
/**
* Obtain the address which is to be used within sender references when
* sending to the given other address or none if the other address cannot be
* reached from this system (i.e. no means of communication known; no
* attempt is made to verify actual reachability).
*/
def getExternalAddressFor(addr: Address): Option[Address]
}
/**
@ -529,6 +537,8 @@ class LocalActorRefProvider(
new RoutedActorRef(system, props.withRouter(d.routerConfig), supervisor, path)
}
}
def getExternalAddressFor(addr: Address): Option[Address] = if (addr == rootPath.address) Some(addr) else None
}
class LocalDeathWatch(val mapSize: Int) extends DeathWatch with ActorClassification {

View file

@ -45,6 +45,7 @@ final case class Address(protocol: String, system: String, host: Option[String],
object Address {
def apply(protocol: String, system: String) = new Address(protocol, system)
def apply(protocol: String, system: String, host: String, port: Int) = new Address(protocol, system, Some(host), Some(port))
}
object RelativeActorPath {

View file

@ -33,6 +33,7 @@ final case class Deploy(
def this(routing: RouterConfig) = this("", ConfigFactory.empty, routing)
def this(routing: RouterConfig, scope: Scope) = this("", ConfigFactory.empty, routing, scope)
def this(scope: Scope) = this("", ConfigFactory.empty, NoRouter, scope)
/**
* Do a merge between this and the other Deploy, where values from this take

View file

@ -41,11 +41,16 @@ guarantee!).
How is Remoting Used?
---------------------
We took the idea of transparency to the limit in that there is no API for the
remoting layer of Akka: it is purely driven by configuration. Just write your
application according to the principles outlined in the previous sections, then
specify remote deployment of actor sub-trees in the configuration file. This
way, your application can be scaled out without having to touch the code.
We took the idea of transparency to the limit in that there is nearly no API
for the remoting layer of Akka: it is purely driven by configuration. Just
write your application according to the principles outlined in the previous
sections, then specify remote deployment of actor sub-trees in the
configuration file. This way, your application can be scaled out without having
to touch the code. The only piece of the API which allows programmatic
influence on remote deployment is that :class:`Props` contain a field which may
be set to a specific :class:`Deploy` instance; this has the same effect as
putting an equivalent deployment into the configuration file (if both are
given, configuration file wins).
Marking Points for Scaling Up with Routers
------------------------------------------

View file

@ -0,0 +1,8 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.docs.remoting
import org.scalatest.junit.JUnitSuite
class RemoteDeploymentDocTest extends RemoteDeploymentDocTestBase with JUnitSuite

View file

@ -0,0 +1,46 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.docs.remoting;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
//#import
import akka.actor.ActorRef;
import akka.actor.Address;
import akka.actor.AddressExtractor;
import akka.actor.Deploy;
import akka.actor.Props;
import akka.actor.ActorSystem;
import akka.remote.RemoteScope;
//#import
public class RemoteDeploymentDocTestBase {
static ActorSystem system;
@BeforeClass
public static void init() {
system = ActorSystem.create();
}
@AfterClass
public static void cleanup() {
system.shutdown();
}
@Test
public void demonstrateDeployment() {
//#make-address
Address addr = new Address("akka", "sys", "host", 1234);
addr = AddressExtractor.parse("akka://sys@host:1234"); // the same
//#make-address
//#deploy
ActorRef ref = system.actorOf(new Props(RemoteDeploymentDocSpec.Echo.class).withDeploy(new Deploy(new RemoteScope(addr))));
//#deploy
assert ref.path().address().equals(addr);
}
}

View file

@ -36,8 +36,12 @@ to your ``application.conf`` file::
As you can see in the example above there are four things you need to add to get started:
* Change provider from ``akka.actor.LocalActorRefProvider`` to ``akka.remote.RemoteActorRefProvider``
* Add host name - the machine you want to run the actor system on
* Add port number - the port the actor system should listen on
* Add host name - the machine you want to run the actor system on; this host
name is exactly what is passed to remote systems in order to identify this
system and consequently used for connecting back to this system if need be,
hence set it to a reachable IP address or resolvable name in case you want to
communicate across the network.
* Add port number - the port the actor system should listen on, set to 0 to have it chosen automatically
The example above only illustrates the bare minimum of properties you have to add to enable remoting.
There are lots of more properties that are related to remoting in Akka. We refer to the following
@ -63,7 +67,7 @@ Creating Actors Remotely
^^^^^^^^^^^^^^^^^^^^^^^^
The configuration below instructs the system to deploy the actor "retrieval” on the specific host "app@10.0.0.1".
The "app" in this case refers to the name of the ``ActorSystem``::
The "app" in this case refers to the name of the ``ActorSystem`` (only showing deployment section)::
akka {
actor {
@ -88,6 +92,27 @@ As you can see from the example above the following pattern is used to find an `
akka://<actorsystemname>@<hostname>:<port>/<actor path>
Programmatic Remote Deployment
------------------------------
To allow dynamically deployed systems, it is also possible to include
deployment configuration in the :class:`Props` which are used to create an
actor: this information is the equivalent of a deployment section from the
configuration file, and if both are given, the external configuration takes
precedence.
With these imports:
.. includecode:: code/akka/docs/remoting/RemoteDeploymentDocTestBase.java#import
and a remote address like this:
.. includecode:: code/akka/docs/remoting/RemoteDeploymentDocTestBase.java#make-address
you can advise the system to create a child on that remote node like so:
.. includecode:: code/akka/docs/remoting/RemoteDeploymentDocTestBase.java#deploy
Serialization
^^^^^^^^^^^^^
@ -122,9 +147,12 @@ the two given target nodes.
Description of the Remoting Sample
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The sample application included with the Akka sources demonstrates both, remote
deployment and look-up of remote actors. First, let us have a look at the
common setup for both scenarios (this is ``common.conf``):
There is a more extensive remote example that comes with the Akka distribution.
Please have a look here for more information: `Remote Sample
<https://github.com/jboner/akka/tree/master/akka-samples/akka-sample-remote>`_
This sample demonstrates both, remote deployment and look-up of remote actors.
First, let us have a look at the common setup for both scenarios (this is
``common.conf``):
.. includecode:: ../../akka-samples/akka-sample-remote/src/main/resources/common.conf

View file

@ -0,0 +1,52 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.docs.remoting
import akka.actor.{ ExtendedActorSystem, ActorSystem, Actor, ActorRef }
import akka.testkit.{ AkkaSpec, ImplicitSender }
//#import
import akka.actor.{ Props, Deploy, Address, AddressExtractor }
import akka.remote.RemoteScope
//#import
object RemoteDeploymentDocSpec {
class Echo extends Actor {
def receive = {
case x sender ! self
}
}
}
class RemoteDeploymentDocSpec extends AkkaSpec("""
akka.actor.provider = "akka.remote.RemoteActorRefProvider"
akka.remote.netty.port = 0
""") with ImplicitSender {
import RemoteDeploymentDocSpec._
val other = ActorSystem("remote", system.settings.config)
val address = other.asInstanceOf[ExtendedActorSystem].provider.getExternalAddressFor(Address("akka", "s", Some("host"), Some(1))).get
override def atTermination() { other.shutdown() }
"demonstrate programmatic deployment" in {
//#deploy
val ref = system.actorOf(Props[Echo].withDeploy(Deploy(scope = RemoteScope(address))))
//#deploy
ref.path.address must be(address)
ref ! "test"
expectMsgType[ActorRef].path.address must be(address)
}
"demonstrate address extractor" in {
//#make-address
val one = AddressExtractor("akka://sys@host:1234")
val two = Address("akka", "sys", "host", 1234) // this gives the same
//#make-address
one must be === two
}
}

View file

@ -4,6 +4,11 @@
Remoting (Scala)
#################
.. sidebar:: Contents
.. contents:: :local:
For an introduction of remoting capabilities of Akka please see :ref:`remoting`.
Preparing your ActorSystem for Remoting
@ -32,8 +37,12 @@ to your ``application.conf`` file::
As you can see in the example above there are four things you need to add to get started:
* Change provider from ``akka.actor.LocalActorRefProvider`` to ``akka.remote.RemoteActorRefProvider``
* Add host name - the machine you want to run the actor system on
* Add port number - the port the actor system should listen on
* Add host name - the machine you want to run the actor system on; this host
name is exactly what is passed to remote systems in order to identify this
system and consequently used for connecting back to this system if need be,
hence set it to a reachable IP address or resolvable name in case you want to
communicate across the network.
* Add port number - the port the actor system should listen on, set to 0 to have it chosen automatically
The example above only illustrates the bare minimum of properties you have to add to enable remoting.
There are lots of more properties that are related to remoting in Akka. We refer to the following
@ -63,7 +72,7 @@ As you can see from the example above the following pattern is used to find an `
akka://<actor system>@<hostname>:<port>/<actor path>
Once you a reference to the actor you can interact with it they same way you would with a local actor, e.g.::
Once you obtained a reference to the actor you can interact with it they same way you would with a local actor, e.g.::
actor ! "Pretty awesome feature"
@ -73,18 +82,19 @@ Creating Actors Remotely
^^^^^^^^^^^^^^^^^^^^^^^^
If you want to use the creation functionality in Akka remoting you have to further amend the
``application.conf`` file in the following way::
``application.conf`` file in the following way (only showing deployment section)::
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
deployment { /sampleActor {
remote = "akka://sampleActorSystem@127.0.0.1:2553"
}}
deployment {
/sampleActor {
remote = "akka://sampleActorSystem@127.0.0.1:2553"
}
}
}
...
}
The configuration above instructs Akka to react when an actor with path /sampleActor is created, i.e.
The configuration above instructs Akka to react when an actor with path ``/sampleActor`` is created, i.e.
using ``system.actorOf(Props(...)`, sampleActor)``. This specific actor will not be directly instantiated,
but instead the remote daemon of the remote system will be asked to create the actor,
which in this sample corresponds to ``sampleActorSystem@127.0.0.1:2553``.
@ -99,12 +109,26 @@ Once you have configured the properties above you would do the following in code
``SampleActor`` has to be available to the runtimes using it, i.e. the classloader of the
actor systems has to have a JAR containing the class.
Remote Sample Code
^^^^^^^^^^^^^^^^^^
Programmatic Remote Deployment
------------------------------
There is a more extensive remote example that comes with the Akka distribution.
Please have a look here for more information:
`Remote Sample <https://github.com/jboner/akka/tree/master/akka-samples/akka-sample-remote>`_
To allow dynamically deployed systems, it is also possible to include
deployment configuration in the :class:`Props` which are used to create an
actor: this information is the equivalent of a deployment section from the
configuration file, and if both are given, the external configuration takes
precedence.
With these imports:
.. includecode:: code/akka/docs/remoting/RemoteDeploymentDocSpec.scala#import
and a remote address like this:
.. includecode:: code/akka/docs/remoting/RemoteDeploymentDocSpec.scala#make-address
you can advise the system to create a child on that remote node like so:
.. includecode:: code/akka/docs/remoting/RemoteDeploymentDocSpec.scala#deploy
Serialization
^^^^^^^^^^^^^
@ -140,9 +164,12 @@ the two given target nodes.
Description of the Remoting Sample
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The sample application included with the Akka sources demonstrates both, remote
deployment and look-up of remote actors. First, let us have a look at the
common setup for both scenarios (this is ``common.conf``):
There is a more extensive remote example that comes with the Akka distribution.
Please have a look here for more information: `Remote Sample
<https://github.com/jboner/akka/tree/master/akka-samples/akka-sample-remote>`_
This sample demonstrates both, remote deployment and look-up of remote actors.
First, let us have a look at the common setup for both scenarios (this is
``common.conf``):
.. includecode:: ../../akka-samples/akka-sample-remote/src/main/resources/common.conf

View file

@ -206,6 +206,16 @@ class RemoteActorRefProvider(
// we dont wait for the ACK, because the remote end will process this command before any other message to the new actor
actorFor(RootActorPath(path.address) / "remote") ! DaemonMsgCreate(props, deploy, path.toString, supervisor)
}
def getExternalAddressFor(addr: Address): Option[Address] = {
val ta = transport.address
val ra = rootPath.address
addr match {
case `ta` | `ra` Some(rootPath.address)
case Address("akka", _, Some(_), Some(_)) Some(transport.address)
case _ None
}
}
}
trait RemoteRef extends ActorRefScope {