Merge remote-tracking branch 'origin/master' into wip-1581-patterns-ask

This commit is contained in:
Roland 2012-01-18 14:20:13 +01:00
commit 1daaee98aa
141 changed files with 4660 additions and 5579 deletions

View file

@ -4,6 +4,7 @@
package akka.docs.actor;
//#imports
import akka.dispatch.*;
import akka.actor.*;
import akka.japi.*;
@ -103,15 +104,14 @@ public class TypedActorDocTestBase {
try {
//#typed-actor-create1
Squarer mySquarer =
TypedActor.get(system).typedActorOf(Squarer.class, SquarerImpl.class, new Props());
TypedActor.get(system).typedActorOf(new TypedProps<SquarerImpl>(Squarer.class, SquarerImpl.class));
//#typed-actor-create1
//#typed-actor-create2
Squarer otherSquarer =
TypedActor.get(system).typedActorOf(Squarer.class,
TypedActor.get(system).typedActorOf(new TypedProps<SquarerImpl>(Squarer.class,
new Creator<SquarerImpl>() {
public SquarerImpl create() { return new SquarerImpl("foo"); }
},
new Props(),
}),
"name");
//#typed-actor-create2

View file

@ -29,6 +29,14 @@ import akka.japi.Procedure;
import akka.actor.Terminated;
//#import-watch
//#import-gracefulStop
import static akka.pattern.Patterns.gracefulStop;
import akka.dispatch.Future;
import akka.dispatch.Await;
import akka.util.Duration;
import akka.actor.ActorTimeoutException;
//#import-gracefulStop
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.actor.UntypedActorFactory;
@ -59,7 +67,6 @@ public class UntypedActorDocTestBase {
return new MyUntypedActor();
}
});
Props props5 = props4.withTimeout(new Timeout(1000));
//#creating-props-config
}
@ -102,8 +109,7 @@ public class UntypedActorDocTestBase {
public void propsActorOf() {
ActorSystem system = ActorSystem.create("MySystem");
//#creating-props
ActorRef myActor = system.actorOf(new Props(MyUntypedActor.class).withDispatcher("my-dispatcher"),
"myactor");
ActorRef myActor = system.actorOf(new Props(MyUntypedActor.class).withDispatcher("my-dispatcher"), "myactor");
//#creating-props
myActor.tell("test");
system.shutdown();
@ -176,6 +182,23 @@ public class UntypedActorDocTestBase {
system.shutdown();
}
@Test
public void usePatternsGracefulStop() {
ActorSystem system = ActorSystem.create("MySystem");
ActorRef actorRef = system.actorOf(new Props(MyUntypedActor.class));
//#gracefulStop
try {
Future<Boolean> stopped = gracefulStop(actorRef, Duration.create(5, TimeUnit.SECONDS), system);
Await.result(stopped, Duration.create(6, TimeUnit.SECONDS));
// the actor has been stopped
} catch (ActorTimeoutException e) {
// the actor wasn't stopped within 5 seconds
}
//#gracefulStop
system.shutdown();
}
public static class MyActor extends UntypedActor {
public MyActor(String s) {
@ -266,6 +289,7 @@ public class UntypedActorDocTestBase {
}
}
}
//#hot-swap-actor
//#watch

View file

@ -0,0 +1,5 @@
package akka.docs.jrouting;
import org.scalatest.junit.JUnitSuite
class CustomRouterDocTest extends CustomRouterDocTestBase with JUnitSuite

View file

@ -0,0 +1,145 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.docs.jrouting;
import java.util.List;
import java.util.Arrays;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import akka.actor.*;
import akka.routing.*;
import akka.util.Duration;
import akka.util.Timeout;
import akka.dispatch.Await;
import akka.dispatch.Future;
import akka.testkit.AkkaSpec;
import com.typesafe.config.ConfigFactory;
import static akka.pattern.Patterns.ask;
import static akka.docs.jrouting.CustomRouterDocTestBase.DemocratActor;
import static akka.docs.jrouting.CustomRouterDocTestBase.RepublicanActor;
import static akka.docs.jrouting.CustomRouterDocTestBase.Message.*;
public class CustomRouterDocTestBase {
ActorSystem system;
@Before
public void setUp() {
system = ActorSystem.create("MySystem", AkkaSpec.testConf());
}
@After
public void tearDown() {
system.shutdown();
}
//#crTest
@Test
public void countVotesAsIntendedNotAsInFlorida() {
ActorRef routedActor = system.actorOf(new Props().withRouter(new VoteCountRouter()));
routedActor.tell(DemocratVote);
routedActor.tell(DemocratVote);
routedActor.tell(RepublicanVote);
routedActor.tell(DemocratVote);
routedActor.tell(RepublicanVote);
Timeout timeout = new Timeout(Duration.parse("1 seconds"));
Future<Object> democratsResult = ask(routedActor, DemocratCountResult, timeout);
Future<Object> republicansResult = ask(routedActor, RepublicanCountResult, timeout);
assertEquals(3, Await.result(democratsResult, timeout.duration()));
assertEquals(2, Await.result(republicansResult, timeout.duration()));
}
//#crTest
//#CustomRouter
//#crMessages
enum Message {
DemocratVote, DemocratCountResult, RepublicanVote, RepublicanCountResult
}
//#crMessages
//#crActors
public static class DemocratActor extends UntypedActor {
int counter = 0;
public void onReceive(Object msg) {
switch ((Message) msg) {
case DemocratVote:
counter++;
break;
case DemocratCountResult:
getSender().tell(counter, getSelf());
break;
default:
unhandled(msg);
}
}
}
public static class RepublicanActor extends UntypedActor {
int counter = 0;
public void onReceive(Object msg) {
switch ((Message) msg) {
case RepublicanVote:
counter++;
break;
case RepublicanCountResult:
getSender().tell(counter, getSelf());
break;
default:
unhandled(msg);
}
}
}
//#crActors
//#crRouter
public static class VoteCountRouter extends CustomRouterConfig {
//#crRoute
@Override
public CustomRoute createCustomRoute(Props props, RouteeProvider routeeProvider) {
final ActorRef democratActor = routeeProvider.context().actorOf(new Props(DemocratActor.class), "d");
final ActorRef republicanActor = routeeProvider.context().actorOf(new Props(RepublicanActor.class), "r");
List<ActorRef> routees = Arrays.asList(new ActorRef[] { democratActor, republicanActor });
//#crRegisterRoutees
routeeProvider.registerRoutees(routees);
//#crRegisterRoutees
//#crRoutingLogic
return new CustomRoute() {
@Override
public Iterable<Destination> destinationsFor(ActorRef sender, Object msg) {
switch ((Message) msg) {
case DemocratVote:
case DemocratCountResult:
return Arrays.asList(new Destination[] { new Destination(sender, democratActor) });
case RepublicanVote:
case RepublicanCountResult:
return Arrays.asList(new Destination[] { new Destination(sender, republicanActor) });
default:
throw new IllegalArgumentException("Unknown message: " + msg);
}
}
};
//#crRoutingLogic
}
//#crRoute
}
//#crRouter
//#CustomRouter
}

View file

@ -0,0 +1,48 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.docs.jrouting;
import java.io.Serializable;
import akka.actor.UntypedActor;
//#fibonacciActor
public class FibonacciActor extends UntypedActor {
public void onReceive(Object msg) {
if (msg instanceof FibonacciNumber) {
FibonacciNumber fibonacciNumber = (FibonacciNumber) msg;
getSender().tell(fibonacci(fibonacciNumber.getNbr()));
} else {
unhandled(msg);
}
}
private int fibonacci(int n) {
return fib(n, 1, 0);
}
private int fib(int n, int b, int a) {
if (n == 0)
return a;
// recursion
return fib(n - 1, a + b, b);
}
public static class FibonacciNumber implements Serializable {
private static final long serialVersionUID = 1L;
private final int nbr;
public FibonacciNumber(int nbr) {
this.nbr = nbr;
}
public int getNbr() {
return nbr;
}
}
}
//#fibonacciActor

View file

@ -0,0 +1,69 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.docs.jrouting;
import akka.routing.ScatterGatherFirstCompletedRouter;
import akka.routing.BroadcastRouter;
import akka.routing.RandomRouter;
import akka.routing.RoundRobinRouter;
import akka.routing.SmallestMailboxRouter;
import akka.actor.UntypedActor;
import akka.actor.ActorRef;
import akka.actor.Props;
import akka.util.Duration;
import akka.util.Timeout;
import akka.dispatch.Future;
import akka.dispatch.Await;
//#parentActor
public class ParentActor extends UntypedActor {
public void onReceive(Object msg) {
if (msg.equals("rrr")) {
//#roundRobinRouter
ActorRef roundRobinRouter = getContext().actorOf(
new Props(PrintlnActor.class).withRouter(new RoundRobinRouter(5)), "router");
for (int i = 1; i <= 10; i++) {
roundRobinRouter.tell(i, getSelf());
}
//#roundRobinRouter
} else if (msg.equals("rr")) {
//#randomRouter
ActorRef randomRouter = getContext().actorOf(new Props(PrintlnActor.class).withRouter(new RandomRouter(5)),
"router");
for (int i = 1; i <= 10; i++) {
randomRouter.tell(i, getSelf());
}
//#randomRouter
} else if (msg.equals("smr")) {
//#smallestMailboxRouter
ActorRef smallestMailboxRouter = getContext().actorOf(
new Props(PrintlnActor.class).withRouter(new SmallestMailboxRouter(5)), "router");
for (int i = 1; i <= 10; i++) {
smallestMailboxRouter.tell(i, getSelf());
}
//#smallestMailboxRouter
} else if (msg.equals("br")) {
//#broadcastRouter
ActorRef broadcastRouter = getContext().actorOf(new Props(PrintlnActor.class).withRouter(new BroadcastRouter(5)),
"router");
broadcastRouter.tell("this is a broadcast message", getSelf());
//#broadcastRouter
} else if (msg.equals("sgfcr")) {
//#scatterGatherFirstCompletedRouter
ActorRef scatterGatherFirstCompletedRouter = getContext().actorOf(
new Props(FibonacciActor.class).withRouter(new ScatterGatherFirstCompletedRouter(5, Duration
.parse("2 seconds"))), "router");
Timeout timeout = getContext().system().settings().ActorTimeout();
Future<Object> futureResult = akka.pattern.Patterns.ask(
scatterGatherFirstCompletedRouter, new FibonacciActor.FibonacciNumber(10), timeout);
int result = (Integer) Await.result(futureResult, timeout.duration());
//#scatterGatherFirstCompletedRouter
System.out.println(String.format("The result of calculating Fibonacci for 10 is %d", result));
} else {
unhandled(msg);
}
}
}
//#parentActor

View file

@ -0,0 +1,15 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.docs.jrouting;
import akka.actor.UntypedActor;
//#printlnActor
public class PrintlnActor extends UntypedActor {
public void onReceive(Object msg) {
System.out.println(String.format("Received message '%s' in actor %s", msg, getSelf().path().name()));
}
}
//#printlnActor

View file

@ -0,0 +1,58 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.docs.jrouting;
import akka.routing.FromConfig;
import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.actor.ActorSystem;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.Config;
public class RouterViaConfigExample {
public static class ExampleActor extends UntypedActor {
public void onReceive(Object msg) {
if (msg instanceof Message) {
Message message = (Message) msg;
System.out.println(String.format("Received %s in router %s", message.getNbr(), getSelf().path().name()));
} else {
unhandled(msg);
}
}
public static class Message {
private final int nbr;
public Message(int nbr) {
this.nbr = nbr;
}
public int getNbr() {
return nbr;
}
}
}
public static void main(String... args) {
Config config = ConfigFactory.parseString("akka.actor.deployment {\n" + " /router {\n"
+ " router = round-robin\n" + " nr-of-instances = 5\n" + " }\n" + "}\n");
ActorSystem system = ActorSystem.create("Example", config);
//#configurableRouting
ActorRef router = system.actorOf(new Props(ExampleActor.class).withRouter(new FromConfig()), "router");
//#configurableRouting
for (int i = 1; i <= 10; i++) {
router.tell(new ExampleActor.Message(i));
}
//#configurableRoutingWithResizer
ActorRef router2 = system.actorOf(new Props(ExampleActor.class).withRouter(new FromConfig()), "router2");
//#configurableRoutingWithResizer
for (int i = 1; i <= 10; i++) {
router2.tell(new ExampleActor.Message(i));
}
}
}

View file

@ -0,0 +1,71 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.docs.jrouting;
import akka.routing.RoundRobinRouter;
import akka.routing.DefaultResizer;
import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.actor.ActorSystem;
import java.util.Arrays;
public class RouterViaProgramExample {
public static class ExampleActor extends UntypedActor {
public void onReceive(Object msg) {
if (msg instanceof Message) {
Message message = (Message) msg;
System.out.println(String.format("Received %s in router %s", message.getNbr(), getSelf().path().name()));
} else {
unhandled(msg);
}
}
public static class Message {
private final int nbr;
public Message(int nbr) {
this.nbr = nbr;
}
public int getNbr() {
return nbr;
}
}
}
public static void main(String... args) {
ActorSystem system = ActorSystem.create("RPE");
//#programmaticRoutingNrOfInstances
int nrOfInstances = 5;
ActorRef router1 = system.actorOf(new Props(ExampleActor.class).withRouter(new RoundRobinRouter(nrOfInstances)));
//#programmaticRoutingNrOfInstances
for (int i = 1; i <= 6; i++) {
router1.tell(new ExampleActor.Message(i));
}
//#programmaticRoutingRoutees
ActorRef actor1 = system.actorOf(new Props(ExampleActor.class));
ActorRef actor2 = system.actorOf(new Props(ExampleActor.class));
ActorRef actor3 = system.actorOf(new Props(ExampleActor.class));
Iterable<ActorRef> routees = Arrays.asList(new ActorRef[] { actor1, actor2, actor3 });
ActorRef router2 = system.actorOf(new Props(ExampleActor.class).withRouter(RoundRobinRouter.create(routees)));
//#programmaticRoutingRoutees
for (int i = 1; i <= 6; i++) {
router2.tell(new ExampleActor.Message(i));
}
//#programmaticRoutingWithResizer
int lowerBound = 2;
int upperBound = 15;
DefaultResizer resizer = new DefaultResizer(lowerBound, upperBound);
ActorRef router3 = system.actorOf(new Props(ExampleActor.class).withRouter(new RoundRobinRouter(nrOfInstances)));
//#programmaticRoutingWithResizer
for (int i = 1; i <= 6; i++) {
router3.tell(new ExampleActor.Message(i));
}
}
}

View file

@ -166,7 +166,7 @@ if not specified otherwise.
default-dispatcher {
# If negative (or zero) then an unbounded mailbox is used (default)
# If positive then a bounded mailbox is used and the capacity is set to the number specified
task-queue-size = 1000
mailbox-capacity = 1000
}
}
}

View file

@ -17,8 +17,13 @@ as illustrated in this example:
.. includecode:: code/akka/docs/event/LoggingDocTestBase.java
:include: imports,my-actor
The second parameter to the ``Logging.getLogger`` is the source of this logging channel.
The source object is translated to a String according to the following rules:
The first parameter to ``Logging.getLogger`` could also be any
:class:`LoggingBus`, specifically ``system.eventStream()``; in the demonstrated
case, the actor systems address is included in the ``akkaSource``
representation of the log source (see `Logging Thread and Akka Source in MDC`_)
while in the second case this is not automatically done. The second parameter
to ``Logging.getLogger`` is the source of this logging channel. The source
object is translated to a String according to the following rules:
* if it is an Actor or ActorRef, its path is used
* in case of a String it is used as is
@ -28,6 +33,13 @@ The source object is translated to a String according to the following rules:
The log message may contain argument placeholders ``{}``, which will be substituted if the log level
is enabled.
The Java :class:`Class` of the log source is also included in the generated
:class:`LogEvent`. In case of a simple string this is replaced with a “marker”
class :class:`akka.event.DummyClassForStringSources` in order to allow special
treatment of this case, e.g. in the SLF4J event listener which will then use
the string instead of the class name for looking up the logger instance to
use.
Event Handler
=============
@ -83,8 +95,8 @@ creating the ``LoggingAdapter`` correspond to the name of the SL4FJ logger.
loglevel = "DEBUG"
}
Logging thread in MDC
---------------------
Logging Thread and Akka Source in MDC
-------------------------------------
Since the logging is done asynchronously the thread in which the logging was performed is captured in
Mapped Diagnostic Context (MDC) with attribute name ``sourceThread``.
@ -96,3 +108,22 @@ With Logback the thread name is available with ``%X{sourceThread}`` specifier wi
</layout>
</appender>
.. note::
It will probably be a good idea to use the ``sourceThread`` MDC value also in
non-Akka parts of the application in order to have this property consistently
available in the logs.
Another helpful facility is that Akka captures the actors address when
instantiating a logger within it, meaning that the full instance identification
is available for associating log messages e.g. with members of a router. This
information is available in the MDC with attribute name ``akkaSource``::
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout>
<pattern>%date{ISO8601} %-5level %logger{36} %X{akkaSource} - %msg%n</pattern>
</layout>
</appender>
For more details on what this attribute contains—also for non-actors—please see
`How to Log`_.

View file

@ -9,39 +9,42 @@ For an introduction of remoting capabilities of Akka please see :ref:`remoting`.
Preparing your ActorSystem for Remoting
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The Akka remoting is a separate jar file. Make sure that you have a dependency from your project to this jar::
The Akka remoting is a separate jar file. Make sure that you have the following dependency in your project::
akka-remote.jar
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-remote</artifactId>
<version>2.0-SNAPSHOT</version>
</dependency>
First of all you have to change the actor provider from ``LocalActorRefProvider`` to ``RemoteActorRefProvider``::
To enable remote capabilities in your Akka project you should, at a minimum, add the following changes
to your ``application.conf`` file::
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
provider = "akka.remote.RemoteActorRefProvider"
}
}
After that you must also add the following settings::
akka {
remote {
transport = "akka.remote.netty.NettyRemoteSupport"
server {
# The hostname or ip to bind the remoting to,
# InetAddress.getLocalHost.getHostAddress is used if empty
hostname = ""
# The default remote server port clients should connect to.
# Default is 2552 (AKKA)
hostname = "127.0.0.1"
port = 2552
}
}
}
}
These are the bare minimal settings that must exist in order to get started with remoting.
There are, of course, more properties that can be tweaked. We refer to the following
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
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
reference file for more information:
* `reference.conf of akka-remote <https://github.com/jboner/akka/blob/master/akka-remote/src/main/resources/reference.conf#L39>`_
.. literalinclude:: ../../akka-remote/src/main/resources/reference.conf
:language: none
Looking up Remote Actors
^^^^^^^^^^^^^^^^^^^^^^^^
@ -66,7 +69,7 @@ The "app" in this case refers to the name of the ``ActorSystem``::
actor {
deployment {
/serviceA/retrieval {
remote = “akka://app@10.0.0.1:2552”
remote = "akka://app@10.0.0.1:2552"
}
}
}
@ -103,10 +106,10 @@ This is also done via configuration::
actor {
deployment {
/serviceA/aggregation {
router = “round-robin”
router = "round-robin"
nr-of-instances = 10
routees {
nodes = [“akka://app@10.0.0.2:2552”, “akka://app@10.0.0.3:2552”]
target {
nodes = ["akka://app@10.0.0.2:2552", "akka://app@10.0.0.3:2552"]
}
}
}

View file

@ -4,9 +4,270 @@
Routing (Java)
==============
This part of the documentation is not done.
.. sidebar:: Contents
We continuously strive to add and improve the documentation so you may want to have a
look at the `snapshot repository <http://akka.io/docs/akka/snapshot/>`_.
.. contents:: :local:
Akka-core includes some building blocks to build more complex message flow handlers, they are listed and explained below:
Router
------
A Router is an actor that routes incoming messages to outbound actors.
The router routes the messages sent to it to its underlying actors called 'routees'.
Akka comes with some defined routers out of the box, but as you will see in this chapter it
is really easy to create your own. The routers shipped with Akka are:
* ``akka.routing.RoundRobinRouter``
* ``akka.routing.RandomRouter``
* ``akka.routing.SmallestMailboxRouter``
* ``akka.routing.BroadcastRouter``
* ``akka.routing.ScatterGatherFirstCompletedRouter``
Routers Explained
^^^^^^^^^^^^^^^^^
This is an example of how to create a router that is defined in configuration:
.. includecode:: ../scala/code/akka/docs/routing/RouterViaConfigExample.scala#config
.. includecode:: code/akka/docs/jrouting/RouterViaConfigExample.java#configurableRouting
This is an example of how to programatically create a router and set the number of routees it should create:
.. includecode:: code/akka/docs/jrouting/RouterViaProgramExample.java#programmaticRoutingNrOfInstances
You can also give the router already created routees as in:
.. includecode:: code/akka/docs/jrouting/RouterViaProgramExample.java#programmaticRoutingRoutees
When you create a router programatically you define the number of routees *or* you pass already created routees to it.
If you send both parameters to the router *only* the latter will be used, i.e. ``nrOfInstances`` is disregarded.
*It is also worth pointing out that if you define the ``router`` in the configuration file then this value will be used
instead of any programmatically sent parameters.*
Once you have the router actor it is just to send messages to it as you would to any actor:
.. code-block:: java
router.tell(new MyMsg());
The router will apply its behavior to the message it receives and forward it to the routees.
Router usage
^^^^^^^^^^^^
In this section we will describe how to use the different router types.
First we need to create some actors that will be used in the examples:
.. includecode:: code/akka/docs/jrouting/PrintlnActor.java#printlnActor
and
.. includecode:: code/akka/docs/jrouting/FibonacciActor.java#fibonacciActor
RoundRobinRouter
****************
Routes in a `round-robin <http://en.wikipedia.org/wiki/Round-robin>`_ fashion to its routees.
Code example:
.. includecode:: code/akka/docs/jrouting/ParentActor.java#roundRobinRouter
When run you should see a similar output to this:
.. code-block:: scala
Received message '1' in actor $b
Received message '2' in actor $c
Received message '3' in actor $d
Received message '6' in actor $b
Received message '4' in actor $e
Received message '8' in actor $d
Received message '5' in actor $f
Received message '9' in actor $e
Received message '10' in actor $f
Received message '7' in actor $c
If you look closely to the output you can see that each of the routees received two messages which
is exactly what you would expect from a round-robin router to happen.
(The name of an actor is automatically created in the format ``$letter`` unless you specify it -
hence the names printed above.)
RandomRouter
************
As the name implies this router type selects one of its routees randomly and forwards
the message it receives to this routee.
This procedure will happen each time it receives a message.
Code example:
.. includecode:: code/akka/docs/jrouting/ParentActor.java#randomRouter
When run you should see a similar output to this:
.. code-block:: scala
Received message '1' in actor $e
Received message '2' in actor $c
Received message '4' in actor $b
Received message '5' in actor $d
Received message '3' in actor $e
Received message '6' in actor $c
Received message '7' in actor $d
Received message '8' in actor $e
Received message '9' in actor $d
Received message '10' in actor $d
The result from running the random router should be different, or at least random, every time you run it.
Try to run it a couple of times to verify its behavior if you don't trust us.
SmallestMailboxRouter
*********************
A Router that tries to send to the non-suspended routee with fewest messages in mailbox.
The selection is done in this order:
* pick any idle routee (not processing message) with empty mailbox
* pick any routee with empty mailbox
* pick routee with fewest pending messages in mailbox
* pick any remote routee, remote actors are consider lowest priority,
since their mailbox size is unknown
Code example:
.. includecode:: code/akka/docs/jrouting/ParentActor.java#smallestMailboxRouter
BroadcastRouter
***************
A broadcast router forwards the message it receives to *all* its routees.
Code example:
.. includecode:: code/akka/docs/jrouting/ParentActor.java#broadcastRouter
When run you should see a similar output to this:
.. code-block:: scala
Received message 'this is a broadcast message' in actor $f
Received message 'this is a broadcast message' in actor $d
Received message 'this is a broadcast message' in actor $e
Received message 'this is a broadcast message' in actor $c
Received message 'this is a broadcast message' in actor $b
As you can see here above each of the routees, five in total, received the broadcast message.
ScatterGatherFirstCompletedRouter
*********************************
The ScatterGatherFirstCompletedRouter will send the message on to all its routees as a future.
It then waits for first result it gets back. This result will be sent back to original sender.
Code example:
.. includecode:: code/akka/docs/jrouting/ParentActor.java#scatterGatherFirstCompletedRouter
When run you should see this:
.. code-block:: scala
The result of calculating Fibonacci for 10 is 55
From the output above you can't really see that all the routees performed the calculation, but they did!
The result you see is from the first routee that returned its calculation to the router.
Broadcast Messages
^^^^^^^^^^^^^^^^^^
There is a special type of message that will be sent to all routees regardless of the router.
This message is called ``Broadcast`` and is used in the following manner:
.. code-block:: java
router.tell(new Broadcast("Watch out for Davy Jones' locker"));
Only the actual message is forwarded to the routees, i.e. "Watch out for Davy Jones' locker" in the example above.
It is up to the routee implementation whether to handle the broadcast message or not.
Dynamically Resizable Routers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
All routers can be used with a fixed number of routees or with a resize strategy to adjust the number
of routees dynamically.
This is an example of how to create a resizable router that is defined in configuration:
.. includecode:: ../scala/code/akka/docs/routing/RouterViaConfigExample.scala#config-resize
.. includecode:: code/akka/docs/jrouting/RouterViaConfigExample.java#configurableRoutingWithResizer
Several more configuration options are availble and described in ``akka.actor.deployment.default.resizer``
section of the reference :ref:`configuration`.
This is an example of how to programatically create a resizable router:
.. includecode:: code/akka/docs/jrouting/RouterViaProgramExample.java#programmaticRoutingWithResizer
*It is also worth pointing out that if you define the ``router`` in the configuration file then this value
will be used instead of any programmatically sent parameters.*
Custom Router
^^^^^^^^^^^^^
You can also create your own router should you not find any of the ones provided by Akka sufficient for your needs.
In order to roll your own router you have to fulfill certain criteria which are explained in this section.
The router created in this example is a simple vote counter. It will route the votes to specific vote counter actors.
In this case we only have two parties the Republicans and the Democrats. We would like a router that forwards all
democrat related messages to the Democrat actor and all republican related messages to the Republican actor.
We begin with defining the class:
.. includecode:: code/akka/docs/jrouting/CustomRouterDocTestBase.java#crRouter
:exclude: crRoute
The next step is to implement the ``createCustomRoute`` method in the class just defined:
.. includecode:: code/akka/docs/jrouting/CustomRouterDocTestBase.java#crRoute
As you can see above we start off by creating the routees and put them in a collection.
Make sure that you don't miss to implement the line below as it is *really* important.
It registers the routees internally and failing to call this method will
cause a ``ActorInitializationException`` to be thrown when the router is used.
Therefore always make sure to do the following in your custom router:
.. includecode:: code/akka/docs/jrouting/CustomRouterDocTestBase.java#crRegisterRoutees
The routing logic is where your magic sauce is applied. In our example it inspects the message types
and forwards to the correct routee based on this:
.. includecode:: code/akka/docs/jrouting/CustomRouterDocTestBase.java#crRoutingLogic
As you can see above what's returned in the ``CustomRoute`` function, which defines the mapping
from incoming sender/message to a ``List`` of ``Destination(sender, routee)``.
The sender is what "parent" the routee should see - changing this could be useful if you for example want
another actor than the original sender to intermediate the result of the routee (if there is a result).
For more information about how to alter the original sender we refer to the source code of
`ScatterGatherFirstCompletedRouter <https://github.com/jboner/akka/blob/master/akka-actor/src/main/scala/akka/routing/Routing.scala#L375>`_
All in all the custom router looks like this:
.. includecode:: code/akka/docs/jrouting/CustomRouterDocTestBase.java#CustomRouter
If you are interested in how to use the VoteCountRouter it looks like this:
.. includecode:: code/akka/docs/jrouting/CustomRouterDocTestBase.java#crTest
Configured Custom Router
************************
It is possible to define configuration properties for custom routers. In the ``router`` property of the deployment
configuration you define the fully qualified class name of the router class. The router class must extend
``akka.routing.CustomRouterConfig`` and and have constructor with ``com.typesafe.config.Config`` parameter.
The deployment section of the configuration is passed to the constructor.
Custom Resizer
**************
A router with dynamically resizable number of routees is implemented by providing a ``akka.routing.Resizer``
in ``resizer`` method of the ``RouterConfig``. See ``akka.routing.DefaultResizer`` for inspiration
of how to write your own resize strategy.
You can also get some ideas of the routing by looking at the corresponding :ref:`routing-scala` documentation.

View file

@ -21,7 +21,7 @@ Usage
Configuration
-------------
For Akka to know which ``Serializer`` to use for what, you need edit your Akka Configuration,
For Akka to know which ``Serializer`` to use for what, you need edit your :ref:`configuration`,
in the "akka.actor.serializers"-section you bind names to implementations of the ``akka.serialization.Serializer``
you wish to use, like this:
@ -90,5 +90,5 @@ which is done by extending ``akka.serialization.JSerializer``, like this:
:include: imports,my-own-serializer
:exclude: ...
Then you only need to fill in the blanks, bind it to a name in your Akka Configuration and then
Then you only need to fill in the blanks, bind it to a name in your :ref:`configuration` and then
list which classes that should be serialized using it.

View file

@ -485,6 +485,16 @@ Use it like this:
.. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java
:include: import-actors,poison-pill
Graceful Stop
-------------
:meth:`gracefulStop` is useful if you need to wait for termination or compose ordered
termination of several actors:
.. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java
:include: import-gracefulStop,gracefulStop
.. _UntypedActor.HotSwap:
HotSwap