DOC: Routing (Java). See #1600
This commit is contained in:
parent
a8c6a0d891
commit
ed2b65c402
13 changed files with 670 additions and 76 deletions
|
|
@ -13,28 +13,28 @@ import akka.util.duration._
|
||||||
object DeployerSpec {
|
object DeployerSpec {
|
||||||
val deployerConf = ConfigFactory.parseString("""
|
val deployerConf = ConfigFactory.parseString("""
|
||||||
akka.actor.deployment {
|
akka.actor.deployment {
|
||||||
/user/service1 {
|
/service1 {
|
||||||
}
|
}
|
||||||
/user/service3 {
|
/service3 {
|
||||||
create-as {
|
create-as {
|
||||||
class = "akka.actor.DeployerSpec$RecipeActor"
|
class = "akka.actor.DeployerSpec$RecipeActor"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/user/service-direct {
|
/service-direct {
|
||||||
router = from-code
|
router = from-code
|
||||||
}
|
}
|
||||||
/user/service-direct2 {
|
/service-direct2 {
|
||||||
router = from-code
|
router = from-code
|
||||||
# nr-of-instances ignored when router = direct
|
# nr-of-instances ignored when router = direct
|
||||||
nr-of-instances = 2
|
nr-of-instances = 2
|
||||||
}
|
}
|
||||||
/user/service-round-robin {
|
/service-round-robin {
|
||||||
router = round-robin
|
router = round-robin
|
||||||
}
|
}
|
||||||
/user/service-random {
|
/service-random {
|
||||||
router = random
|
router = random
|
||||||
}
|
}
|
||||||
/user/service-scatter-gather {
|
/service-scatter-gather {
|
||||||
router = scatter-gather
|
router = scatter-gather
|
||||||
within = 2 seconds
|
within = 2 seconds
|
||||||
}
|
}
|
||||||
|
|
@ -53,7 +53,7 @@ class DeployerSpec extends AkkaSpec(DeployerSpec.deployerConf) {
|
||||||
"A Deployer" must {
|
"A Deployer" must {
|
||||||
|
|
||||||
"be able to parse 'akka.actor.deployment._' with all default values" in {
|
"be able to parse 'akka.actor.deployment._' with all default values" in {
|
||||||
val service = "/user/service1"
|
val service = "/service1"
|
||||||
val deployment = system.asInstanceOf[ActorSystemImpl].provider.deployer.lookup(service)
|
val deployment = system.asInstanceOf[ActorSystemImpl].provider.deployer.lookup(service)
|
||||||
deployment must be('defined)
|
deployment must be('defined)
|
||||||
|
|
||||||
|
|
@ -67,13 +67,13 @@ class DeployerSpec extends AkkaSpec(DeployerSpec.deployerConf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
"use None deployment for undefined service" in {
|
"use None deployment for undefined service" in {
|
||||||
val service = "/user/undefined"
|
val service = "/undefined"
|
||||||
val deployment = system.asInstanceOf[ActorSystemImpl].provider.deployer.lookup(service)
|
val deployment = system.asInstanceOf[ActorSystemImpl].provider.deployer.lookup(service)
|
||||||
deployment must be(None)
|
deployment must be(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
"be able to parse 'akka.actor.deployment._' with recipe" in {
|
"be able to parse 'akka.actor.deployment._' with recipe" in {
|
||||||
val service = "/user/service3"
|
val service = "/service3"
|
||||||
val deployment = system.asInstanceOf[ActorSystemImpl].provider.deployer.lookup(service)
|
val deployment = system.asInstanceOf[ActorSystemImpl].provider.deployer.lookup(service)
|
||||||
deployment must be('defined)
|
deployment must be('defined)
|
||||||
|
|
||||||
|
|
@ -90,7 +90,7 @@ class DeployerSpec extends AkkaSpec(DeployerSpec.deployerConf) {
|
||||||
intercept[com.typesafe.config.ConfigException.WrongType] {
|
intercept[com.typesafe.config.ConfigException.WrongType] {
|
||||||
val invalidDeployerConf = ConfigFactory.parseString("""
|
val invalidDeployerConf = ConfigFactory.parseString("""
|
||||||
akka.actor.deployment {
|
akka.actor.deployment {
|
||||||
/user/service-invalid-number-of-instances {
|
/service-invalid-number-of-instances {
|
||||||
router = round-robin
|
router = round-robin
|
||||||
nr-of-instances = boom
|
nr-of-instances = boom
|
||||||
}
|
}
|
||||||
|
|
@ -102,23 +102,23 @@ class DeployerSpec extends AkkaSpec(DeployerSpec.deployerConf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
"be able to parse 'akka.actor.deployment._' with direct router" in {
|
"be able to parse 'akka.actor.deployment._' with direct router" in {
|
||||||
assertRouting(NoRouter, "/user/service-direct")
|
assertRouting(NoRouter, "/service-direct")
|
||||||
}
|
}
|
||||||
|
|
||||||
"ignore nr-of-instances with direct router" in {
|
"ignore nr-of-instances with direct router" in {
|
||||||
assertRouting(NoRouter, "/user/service-direct2")
|
assertRouting(NoRouter, "/service-direct2")
|
||||||
}
|
}
|
||||||
|
|
||||||
"be able to parse 'akka.actor.deployment._' with round-robin router" in {
|
"be able to parse 'akka.actor.deployment._' with round-robin router" in {
|
||||||
assertRouting(RoundRobinRouter(1), "/user/service-round-robin")
|
assertRouting(RoundRobinRouter(1), "/service-round-robin")
|
||||||
}
|
}
|
||||||
|
|
||||||
"be able to parse 'akka.actor.deployment._' with random router" in {
|
"be able to parse 'akka.actor.deployment._' with random router" in {
|
||||||
assertRouting(RandomRouter(1), "/user/service-random")
|
assertRouting(RandomRouter(1), "/service-random")
|
||||||
}
|
}
|
||||||
|
|
||||||
"be able to parse 'akka.actor.deployment._' with scatter-gather router" in {
|
"be able to parse 'akka.actor.deployment._' with scatter-gather router" in {
|
||||||
assertRouting(ScatterGatherFirstCompletedRouter(nrOfInstances = 1, within = 2 seconds), "/user/service-scatter-gather")
|
assertRouting(ScatterGatherFirstCompletedRouter(nrOfInstances = 1, within = 2 seconds), "/service-scatter-gather")
|
||||||
}
|
}
|
||||||
|
|
||||||
def assertRouting(expected: RouterConfig, service: String) {
|
def assertRouting(expected: RouterConfig, service: String) {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ package akka.routing
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import akka.actor._
|
import akka.actor._
|
||||||
import collection.mutable.LinkedList
|
import scala.collection.mutable.LinkedList
|
||||||
import akka.testkit._
|
import akka.testkit._
|
||||||
import akka.util.duration._
|
import akka.util.duration._
|
||||||
import akka.dispatch.Await
|
import akka.dispatch.Await
|
||||||
|
|
@ -33,8 +33,6 @@ object RoutingSpec {
|
||||||
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
|
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
|
||||||
class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
|
class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
|
||||||
|
|
||||||
val impl = system.asInstanceOf[ActorSystemImpl]
|
|
||||||
|
|
||||||
import akka.routing.RoutingSpec._
|
import akka.routing.RoutingSpec._
|
||||||
|
|
||||||
"routers in general" must {
|
"routers in general" must {
|
||||||
|
|
@ -399,7 +397,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
|
||||||
}
|
}
|
||||||
|
|
||||||
"count votes as intended - not as in Florida" in {
|
"count votes as intended - not as in Florida" in {
|
||||||
val routedActor = system.actorOf(Props[TestActor].withRouter(VoteCountRouter))
|
val routedActor = system.actorOf(Props().withRouter(VoteCountRouter))
|
||||||
routedActor ! DemocratVote
|
routedActor ! DemocratVote
|
||||||
routedActor ! DemocratVote
|
routedActor ! DemocratVote
|
||||||
routedActor ! RepublicanVote
|
routedActor ! RepublicanVote
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package akka.docs.jrouting;
|
||||||
|
|
||||||
|
import org.scalatest.junit.JUnitSuite
|
||||||
|
|
||||||
|
class CustomRouterDocTest extends CustomRouterDocTestBase with JUnitSuite
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
/**
|
||||||
|
* 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.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 = routedActor.ask(DemocratCountResult, timeout);
|
||||||
|
Future<Object> republicansResult = routedActor.ask(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, ActorContext context, RoutedActorRef ref) {
|
||||||
|
final ActorRef democratActor = context.actorOf(new Props(DemocratActor.class), "d");
|
||||||
|
final ActorRef republicanActor = context.actorOf(new Props(RepublicanActor.class), "r");
|
||||||
|
List<ActorRef> routees = Arrays.asList(new ActorRef[] { democratActor, republicanActor });
|
||||||
|
|
||||||
|
//#crRegisterRoutees
|
||||||
|
registerRoutees(context, 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
|
||||||
|
|
||||||
|
}
|
||||||
48
akka-docs/java/code/akka/docs/jrouting/FibonacciActor.java
Normal file
48
akka-docs/java/code/akka/docs/jrouting/FibonacciActor.java
Normal 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
|
||||||
|
|
||||||
60
akka-docs/java/code/akka/docs/jrouting/ParentActor.java
Normal file
60
akka-docs/java/code/akka/docs/jrouting/ParentActor.java
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
/**
|
||||||
|
* 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.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("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 = scatterGatherFirstCompletedRouter.ask(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
|
||||||
15
akka-docs/java/code/akka/docs/jrouting/PrintlnActor.java
Normal file
15
akka-docs/java/code/akka/docs/jrouting/PrintlnActor.java
Normal 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
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
/**
|
||||||
|
* 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
|
||||||
|
*/
|
||||||
|
package akka.docs.jrouting;
|
||||||
|
|
||||||
|
import akka.routing.RoundRobinRouter;
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,9 +4,218 @@
|
||||||
Routing (Java)
|
Routing (Java)
|
||||||
==============
|
==============
|
||||||
|
|
||||||
This part of the documentation is not done.
|
.. sidebar:: Contents
|
||||||
|
|
||||||
|
.. 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 four defined routers out of the box, but as you will see in this chapter it
|
||||||
|
is really easy to create your own. The four routers shipped with Akka are:
|
||||||
|
|
||||||
|
* ``akka.routing.RoundRobinRouter``
|
||||||
|
* ``akka.routing.RandomRouter``
|
||||||
|
* ``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 number of routees 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
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/>`_.
|
|
||||||
|
|
||||||
You can also get some ideas of the routing by looking at the corresponding :ref:`routing-scala` documentation.
|
|
||||||
|
|
@ -46,7 +46,7 @@ class ParentActor extends Actor {
|
||||||
case "rrr" ⇒
|
case "rrr" ⇒
|
||||||
//#roundRobinRouter
|
//#roundRobinRouter
|
||||||
val roundRobinRouter =
|
val roundRobinRouter =
|
||||||
context.actorOf(Props[PrintlnActor].withRouter(RoundRobinRouter()), "router")
|
context.actorOf(Props[PrintlnActor].withRouter(RoundRobinRouter(5)), "router")
|
||||||
1 to 10 foreach {
|
1 to 10 foreach {
|
||||||
i ⇒ roundRobinRouter ! i
|
i ⇒ roundRobinRouter ! i
|
||||||
}
|
}
|
||||||
|
|
@ -54,7 +54,7 @@ class ParentActor extends Actor {
|
||||||
case "rr" ⇒
|
case "rr" ⇒
|
||||||
//#randomRouter
|
//#randomRouter
|
||||||
val randomRouter =
|
val randomRouter =
|
||||||
context.actorOf(Props[PrintlnActor].withRouter(RandomRouter()), "router")
|
context.actorOf(Props[PrintlnActor].withRouter(RandomRouter(5)), "router")
|
||||||
1 to 10 foreach {
|
1 to 10 foreach {
|
||||||
i ⇒ randomRouter ! i
|
i ⇒ randomRouter ! i
|
||||||
}
|
}
|
||||||
|
|
@ -62,14 +62,14 @@ class ParentActor extends Actor {
|
||||||
case "br" ⇒
|
case "br" ⇒
|
||||||
//#broadcastRouter
|
//#broadcastRouter
|
||||||
val broadcastRouter =
|
val broadcastRouter =
|
||||||
context.actorOf(Props[PrintlnActor].withRouter(BroadcastRouter()), "router")
|
context.actorOf(Props[PrintlnActor].withRouter(BroadcastRouter(5)), "router")
|
||||||
broadcastRouter ! "this is a broadcast message"
|
broadcastRouter ! "this is a broadcast message"
|
||||||
//#broadcastRouter
|
//#broadcastRouter
|
||||||
case "sgfcr" ⇒
|
case "sgfcr" ⇒
|
||||||
//#scatterGatherFirstCompletedRouter
|
//#scatterGatherFirstCompletedRouter
|
||||||
val scatterGatherFirstCompletedRouter = context.actorOf(
|
val scatterGatherFirstCompletedRouter = context.actorOf(
|
||||||
Props[FibonacciActor].withRouter(ScatterGatherFirstCompletedRouter(within = 2 seconds)),
|
Props[FibonacciActor].withRouter(ScatterGatherFirstCompletedRouter(
|
||||||
"router")
|
nrOfInstances = 5, within = 2 seconds)), "router")
|
||||||
implicit val timeout = context.system.settings.ActorTimeout
|
implicit val timeout = context.system.settings.ActorTimeout
|
||||||
val futureResult = scatterGatherFirstCompletedRouter ? FibonacciNumber(10)
|
val futureResult = scatterGatherFirstCompletedRouter ? FibonacciNumber(10)
|
||||||
val result = Await.result(futureResult, timeout.duration)
|
val result = Await.result(futureResult, timeout.duration)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@
|
||||||
package akka.docs.routing
|
package akka.docs.routing
|
||||||
|
|
||||||
import akka.actor.{ Actor, Props, ActorSystem }
|
import akka.actor.{ Actor, Props, ActorSystem }
|
||||||
import akka.routing.RoundRobinRouter
|
import com.typesafe.config.ConfigFactory
|
||||||
|
import akka.routing.FromConfig
|
||||||
|
|
||||||
case class Message(nbr: Int)
|
case class Message(nbr: Int)
|
||||||
|
|
||||||
|
|
@ -15,10 +16,20 @@ class ExampleActor extends Actor {
|
||||||
}
|
}
|
||||||
|
|
||||||
object RouterWithConfigExample extends App {
|
object RouterWithConfigExample extends App {
|
||||||
val system = ActorSystem("Example")
|
val config = ConfigFactory.parseString("""
|
||||||
|
//#config
|
||||||
|
akka.actor.deployment {
|
||||||
|
/router {
|
||||||
|
router = round-robin
|
||||||
|
nr-of-instances = 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#config
|
||||||
|
""")
|
||||||
|
val system = ActorSystem("Example", config)
|
||||||
//#configurableRouting
|
//#configurableRouting
|
||||||
val router = system.actorOf(Props[PrintlnActor].withRouter(RoundRobinRouter()),
|
val router = system.actorOf(Props[ExampleActor].withRouter(FromConfig()),
|
||||||
"exampleActor")
|
"router")
|
||||||
//#configurableRouting
|
//#configurableRouting
|
||||||
1 to 10 foreach { i ⇒ router ! Message(i) }
|
1 to 10 foreach { i ⇒ router ! Message(i) }
|
||||||
}
|
}
|
||||||
|
|
@ -19,13 +19,41 @@ The router routes the messages sent to it to its underlying actors called 'route
|
||||||
Akka comes with four defined routers out of the box, but as you will see in this chapter it
|
Akka comes with four defined routers out of the box, but as you will see in this chapter it
|
||||||
is really easy to create your own. The four routers shipped with Akka are:
|
is really easy to create your own. The four routers shipped with Akka are:
|
||||||
|
|
||||||
* `RoundRobinRouter <https://github.com/jboner/akka/blob/master/akka-actor/src/main/scala/akka/routing/Routing.scala#L173>`_
|
* ``akka.routing.RoundRobinRouter``
|
||||||
* `RandomRouter <https://github.com/jboner/akka/blob/master/akka-actor/src/main/scala/akka/routing/Routing.scala#L226>`_
|
* ``akka.routing.RandomRouter``
|
||||||
* `BroadcastRouter <https://github.com/jboner/akka/blob/master/akka-actor/src/main/scala/akka/routing/Routing.scala#L284>`_
|
* ``akka.routing.BroadcastRouter``
|
||||||
* `ScatterGatherFirstCompletedRouter <https://github.com/jboner/akka/blob/master/akka-actor/src/main/scala/akka/routing/Routing.scala#L330>`_
|
* ``akka.routing.ScatterGatherFirstCompletedRouter``
|
||||||
|
|
||||||
To illustrate how to use the routers we will create a couple of simple actors and then use them in the
|
Routers Explained
|
||||||
different router types.
|
^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This is an example of how to create a router that is defined in configuration:
|
||||||
|
|
||||||
|
.. includecode:: code/akka/docs/routing/RouterViaConfigExample.scala#config
|
||||||
|
|
||||||
|
.. includecode:: code/akka/docs/routing/RouterViaConfigExample.scala#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/routing/RouterViaProgramExample.scala#programmaticRoutingNrOfInstances
|
||||||
|
|
||||||
|
You can also give the router already created routees as in:
|
||||||
|
|
||||||
|
.. includecode:: code/akka/docs/routing/RouterViaProgramExample.scala#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 number of routees 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:: scala
|
||||||
|
|
||||||
|
router ! MyMsg
|
||||||
|
|
||||||
|
The router will apply its behavior to the message it receives and forward it to the routees.
|
||||||
|
|
||||||
Router usage
|
Router usage
|
||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
|
|
@ -39,13 +67,6 @@ and
|
||||||
|
|
||||||
.. includecode:: code/akka/docs/routing/RouterTypeExample.scala#fibonacciActor
|
.. includecode:: code/akka/docs/routing/RouterTypeExample.scala#fibonacciActor
|
||||||
|
|
||||||
Here is the configuration file to instruct the routers how many instances of routees to create::
|
|
||||||
|
|
||||||
akka.actor.deployment {
|
|
||||||
/router {
|
|
||||||
nr-of-instances = 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RoundRobinRouter
|
RoundRobinRouter
|
||||||
****************
|
****************
|
||||||
|
|
@ -137,34 +158,6 @@ When run you should see this:
|
||||||
From the output above you can't really see that all the routees performed the calculation, but they did!
|
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.
|
The result you see is from the first routee that returned its calculation to the router.
|
||||||
|
|
||||||
Routers Explained
|
|
||||||
^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
In the example usage above we showed you how to use routers configured with a configuration file but routers
|
|
||||||
can also be configured programatically.
|
|
||||||
|
|
||||||
This is an example of how to create a router and set the number of routees it should create:
|
|
||||||
|
|
||||||
.. includecode:: code/akka/docs/routing/RouterViaProgramExample.scala#programmaticRoutingNrOfInstances
|
|
||||||
|
|
||||||
You can also give the router already created routees as in:
|
|
||||||
|
|
||||||
.. includecode:: code/akka/docs/routing/RouterViaProgramExample.scala#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 number of routees 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:: scala
|
|
||||||
|
|
||||||
router ! MyMsg
|
|
||||||
|
|
||||||
The router will apply its behavior to the message it receives and forward it to the routees.
|
|
||||||
|
|
||||||
Broadcast Messages
|
Broadcast Messages
|
||||||
^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|
@ -193,7 +186,7 @@ We begin with defining the class:
|
||||||
.. includecode:: ../../akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala#crRouter
|
.. includecode:: ../../akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala#crRouter
|
||||||
:exclude: crRoute
|
:exclude: crRoute
|
||||||
|
|
||||||
The next step is to implement the 'createRoute' method in the class just defined:
|
The next step is to implement the ``createRoute`` method in the class just defined:
|
||||||
|
|
||||||
.. includecode:: ../../akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala#crRoute
|
.. includecode:: ../../akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala#crRoute
|
||||||
|
|
||||||
|
|
@ -215,7 +208,7 @@ As you can see above what's returned in the partial function is a ``List`` of ``
|
||||||
The sender is what "parent" the routee should see - changing this could be useful if you for example want
|
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).
|
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
|
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#L330>`_
|
`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:
|
All in all the custom router looks like this:
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue