KEMBAR78
Akka Cluster in Java - JCConf 2015 | PDF
#JCConf
Akka Cluster in Java
Jiayun Zhou
jiayun@gmail.com
Introduction
Akka
Concurrent & Distributed
Actor Model
http://blog.shiftehfar.org/?p=431
Scala
Java?
Scala is better
Java
Maven
Basic
pom.xml
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.11</artifactId>
<version>2.4.1</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>typesafe</id>
<name>Typesafe Repository</name>
<url>http://repo.typesafe.com/typesafe/releases/</url>
</repository>
</repositories>
Main.java
public static void main(String[] args) {
// akka.Main.main(new
String[]{HelloWorld.class.getName()});
ActorSystem system = ActorSystem.create("Hello");
ActorRef a =
system.actorOf(Props.create(HelloWorld.class), "helloWorld");
}
HelloWorld Actor
public class HelloWorld extends UntypedActor {
@Override
public void preStart() {
final ActorRef greeter =
getContext().actorOf(Props.create(Greeter.class), "greeter");
greeter.tell(Greeter.Msg.GREET, getSelf());
}
@Override
public void onReceive(Object msg) {
if (msg == Greeter.Msg.DONE) {
getContext().stop(getSelf());
} else
unhandled(msg);
}
}
Greeter Actor
public class Greeter extends UntypedActor {
public static enum Msg {
GREET, DONE;
}
@Override
public void onReceive(Object msg) {
if (msg == Msg.GREET) {
System.out.println("Hello World!");
getSender().tell(Msg.DONE, getSelf());
} else
unhandled(msg);
}
}
Sending message
• tell() – Fire and forget
• ask() – Send and receive
Avoid Ask
• https://www.safaribooksonline.com/library/view/effective-
akka/9781449360061/ch02.html#_avoiding_ask
• https://www.safaribooksonline.com/library/view/effective-
akka/9781449360061/ch03.html#_tell_don_8217_t_ask
Remoting
pom.xml
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-remote_2.11</artifactId>
<version>2.4.1</version>
</dependency>
Local application.conf
LocalSys {
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
}
remote {
enabled-transports = ["akka.remote.netty.tcp"]
netty.tcp {
hostname = "127.0.0.1"
port = 2551
}
}
}
}
Remote application.conf
RemoteSys {
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
}
remote {
enabled-transports = ["akka.remote.netty.tcp"]
netty.tcp {
hostname = "127.0.0.1"
port = 2552
}
}
}
}
Local Main
public static void main(String[] args) throws
Exception {
ActorSystem _system =
ActorSystem.create("LocalNodeApp",ConfigFactory
.load().getConfig("LocalSys"));
ActorRef localActor =
_system.actorOf(Props.create(LocalActor.class));
localActor.tell("Hello", null);
Thread.sleep(5000);
_system.shutdown();
}
Local Actor
ActorRef remoteActor;
@Override
public void preStart() {
//Get a reference to the remote actor
remoteActor = getContext().actorFor(
"akka.tcp://RemoteNodeApp@127.0.0.1:2552/user/remoteActor"
);
}
@Override
public void onReceive(Object message) throws Exception {
Future<Object> future = Patterns.ask(remoteActor,
message.toString(),
timeout);
String result = (String) Await.result(future,
timeout.duration());
log.info("Message received from Server -> {}", result);
}
Actor Path
akka.<protocol>://<actorsystemname>@<hos
tname>:<port>/<actor path>
• http://doc.akka.io/docs/akka/2.4.1/general/addressing.html
Remote Main
public static void main(String[] args) {
final ActorSystem system =
ActorSystem.create("RemoteNodeApp", ConfigFactory
.load().getConfig("RemoteSys"));
system.actorOf(Props.create(RemoteActor.class),
"remoteActor");
Runtime.getRuntime().addShutdownHook(new Thread()
{
@Override
public void run() {
system.shutdown();
}
});
}
Remote Actor
@Override
public void onReceive(Object message) throws
Exception {
if (message instanceof String) {
// Get reference to the message sender and
reply back
log.info("Message received -> {}", message);
getSender().tell(message + " got something",
null);
}
}
Router
Router Main
public static void main(String[] args) throws
InterruptedException {
ActorSystem _system =
ActorSystem.create("RemoteRouteeRouterExample",
ConfigFactory.load().getConfig("MyRouterExample"));
Address[] addresses = new Address[]{
new Address("akka.tcp", "RemoteNodeApp",
"10.211.55.6", 2552),
new Address("akka.tcp", "RemoteNodeApp",
"10.211.55.5", 2552)
};
ActorRef router = _system.actorOf(new RemoteRouterConfig(new
RoundRobinPool(5), addresses).props(
Props.create(RemoteActor.class)));
for (int i = 1; i <= 10; i++) {
// sends randomly to actors
router.tell("Hello " + Integer.toString(i), null);
}
_system.shutdown();
}
Cluster
pom.xml
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-cluster_2.11</artifactId>
<version>2.4.1</version>
</dependency>
application.conf
akka {
actor {
provider = "akka.cluster.ClusterActorRefProvider"
}
remote {
log-remote-lifecycle-events = off
netty.tcp {
hostname = "127.0.0.1"
port = 0
}
}
cluster {
seed-nodes = [
"akka.tcp://ClusterSystem@10.211.55.5:2552",
"akka.tcp://ClusterSystem@10.211.55.6:2552"]
auto-down-unreachable-after = 10s
}
}
Seed Nodes
Member States
Backend Main
public static void main(String[] args) {
// Override the configuration of the port when specified as
program argument
final String hostname = args.length > 0 ? args[0] : "127.0.0.1";
final String port = args.length > 1 ? args[1] : "0";
final Config config =
ConfigFactory.parseString("akka.remote.netty.tcp.hostname=" +
hostname).
withFallback(ConfigFactory.parseString("akka.remote.netty.tcp.port="
+ port)).
withFallback(ConfigFactory.parseString("akka.cluster.roles =
[backend]")).
withFallback(ConfigFactory.load());
ActorSystem system = ActorSystem.create("ClusterSystem", config);
system.actorOf(Props.create(TransformationBackend.class),
"backend");
}
Backend Actor - 1
Cluster cluster = Cluster.get(getContext().system());
//subscribe to cluster changes, MemberUp
@Override
public void preStart() {
cluster.subscribe(getSelf(), MemberUp.class);
}
//re-subscribe when restart
@Override
public void postStop() {
cluster.unsubscribe(getSelf());
}
void register(Member member) {
if (member.hasRole("frontend"))
getContext().actorSelection(member.address() +
"/user/frontend").tell(
BACKEND_REGISTRATION, getSelf());
}
Backend Actor - 2
@Override
public void onReceive(Object message) {
if (message instanceof TransformationJob) {
TransformationJob job = (TransformationJob) message;
getSender().tell(new
TransformationResult(job.getText().toUpperCase()),
getSelf());
} else if (message instanceof CurrentClusterState) {
CurrentClusterState state = (CurrentClusterState) message;
for (Member member : state.getMembers()) {
if (member.status().equals(MemberStatus.up())) {
register(member);
}
}
} else if (message instanceof MemberUp) {
MemberUp mUp = (MemberUp) message;
register(mUp.member());
} else {
unhandled(message);
}
}
Frontend Main - 1
final String hostname = args.length > 0 ? args[0] :
"127.0.0.1";
final String port = args.length > 1 ? args[1] : "0";
final Config config =
ConfigFactory.parseString("akka.remote.netty.tcp.host
name=" + hostname).
withFallback(ConfigFactory.parseString("akka.remote.n
etty.tcp.port=" + port)).
withFallback(ConfigFactory.parseString("akka.cluster.
roles = [frontend]")).
withFallback(ConfigFactory.load());
ActorSystem system =
ActorSystem.create("ClusterSystem", config);
Frontend Main - 2
final ActorRef frontend = system.actorOf(
Props.create(TransformationFrontend.class),
"frontend");
…
system.scheduler().schedule(interval, interval, new
Runnable() {
public void run() {
Patterns.ask(frontend,
new TransformationJob("hello-" +
counter.incrementAndGet()),
timeout).onSuccess(new OnSuccess<Object>()
{
public void onSuccess(Object result) {
System.out.println(result);
}
}, ec);
}
}, ec);
Frontend Actor - 1
List<ActorRef> backends = new ArrayList<ActorRef>();
int jobCounter = 0;
@Override
public void onReceive(Object message) {
if ((message instanceof TransformationJob) &&
backends.isEmpty()) {
TransformationJob job = (TransformationJob)
message;
getSender().tell(
new JobFailed("Service unavailable, try again
later", job),
getSender());
Frontend Actor - 2
} else if (message instanceof TransformationJob) {
TransformationJob job = (TransformationJob) message;
jobCounter++;
backends.get(jobCounter % backends.size())
.forward(job, getContext());
} else if (message.equals(BACKEND_REGISTRATION)) {
getContext().watch(getSender());
backends.add(getSender());
} else if (message instanceof Terminated) {
Terminated terminated = (Terminated) message;
backends.remove(terminated.getActor());
} else {
unhandled(message);
}
}
Run
java -cp .:./*
sample.cluster.transformation.TransformationBackendMa
in 10.211.55.5 2552
java -cp .:./*
sample.cluster.transformation.TransformationBackendMa
in 10.211.55.6 2552
java -cp .:./*
sample.cluster.transformation.TransformationFrontendM
ain 10.211.55.2 2552
Best Practices
• At least two seed nodes
• Use fixed port if possible
Something not mentioned
• Supervision
• Persistence
• …
ZooKeeper
3 ZooKeeper Servers
pom.xml
<dependency>
<groupId>com.sclasen</groupId>
<artifactId>akka-zk-cluster-seed_2.11</artifactId>
<version>0.1.2</version>
</dependency>
application.conf
akka {
loglevel = "DEBUG"
stdout-loglevel = "DEBUG"
actor {
provider = "akka.cluster.ClusterActorRefProvider"
}
remote {
log-remote-lifecycle-events = off
netty.tcp {
hostname = "127.0.0.1"
port = 0
}
}
cluster {
// seed-nodes = [
// "akka.tcp://ClusterSystem@10.211.55.5:2552",
// "akka.tcp://ClusterSystem@10.211.55.6:2552"]
auto-down-unreachable-after = 10s
}
}
reference.conf
akka.cluster.seed.zookeeper {
url = "10.211.55.2:2181,10.211.55.5:2181,10.211.55.6:2181"
path = "/akka/cluster/seed"
}
Join Cluster
ActorSystem system = ActorSystem.create("ClusterSystem", config);
new ZookeeperClusterSeed((ExtendedActorSystem)system).join();
Cluster & Router
factorial.conf - 1
include "application"
# //#min-nr-of-members
akka.cluster.min-nr-of-members = 3
# //#min-nr-of-members
# //#role-min-nr-of-members
akka.cluster.role {
frontend.min-nr-of-members = 1
backend.min-nr-of-members = 2
}
# //#role-min-nr-of-members
factorial.conf - 2
# //#adaptive-router
akka.actor.deployment {
/factorialFrontend/factorialBackendRouter = {
router = adaptive-group
# metrics-selector = heap
# metrics-selector = load
# metrics-selector = cpu
metrics-selector = mix
nr-of-instances = 100
routees.paths = ["/user/factorialBackend"]
cluster {
enabled = on
use-role = backend
allow-local-routees = off
}
}
}
# //#adaptive-router
Backend Main
final String port = args.length > 0 ? args[0] : "0";
final Config config =
ConfigFactory.parseString("akka.remote.netty.tcp.port=" +
port).
withFallback(ConfigFactory.parseString("akka.cluster.roles
= [backend]")).
withFallback(ConfigFactory.load("factorial"));
ActorSystem system = ActorSystem.create("ClusterSystem",
config);
new
ZookeeperClusterSeed((ExtendedActorSystem)system).join();
system.actorOf(Props.create(FactorialBackend.class),
"factorialBackend");
system.actorOf(Props.create(MetricsListener.class),
"metricsListener");
Backend Actor
Frontend Main
final int upToN = 200;
final Config config = ConfigFactory.parseString(
"akka.cluster.roles = [frontend]").withFallback(
ConfigFactory.load("factorial"));
final ActorSystem system =
ActorSystem.create("ClusterSystem", config);
new
ZookeeperClusterSeed((ExtendedActorSystem)system).join();
Cluster.get(system).registerOnMemberUp(new Runnable() {
@Override
public void run() {
system.actorOf(Props.create(FactorialFrontend.class, upToN,
true),
"factorialFrontend");
}
});
Frontend Actor
ActorRef backend =
getContext().actorOf(FromConfig.getInstance().props(),
"factorialBackendRouter");
…
void sendJobs() {
log.info("Starting batch of factorials up to
[{}]", upToN);
for (int n = 1; n <= upToN; n++) {
backend.tell(n, getSelf());
}
}
Resources
Java Sample Code
https://github.com/jiayun/
akka_samples
https://www.safaribooksonlin
e.com/search/?query=Akka&
highlight=true
Thanks

Akka Cluster in Java - JCConf 2015

  • 1.
    #JCConf Akka Cluster inJava Jiayun Zhou jiayun@gmail.com
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 12.
  • 13.
  • 14.
  • 15.
    Main.java public static voidmain(String[] args) { // akka.Main.main(new String[]{HelloWorld.class.getName()}); ActorSystem system = ActorSystem.create("Hello"); ActorRef a = system.actorOf(Props.create(HelloWorld.class), "helloWorld"); }
  • 16.
    HelloWorld Actor public classHelloWorld extends UntypedActor { @Override public void preStart() { final ActorRef greeter = getContext().actorOf(Props.create(Greeter.class), "greeter"); greeter.tell(Greeter.Msg.GREET, getSelf()); } @Override public void onReceive(Object msg) { if (msg == Greeter.Msg.DONE) { getContext().stop(getSelf()); } else unhandled(msg); } }
  • 17.
    Greeter Actor public classGreeter extends UntypedActor { public static enum Msg { GREET, DONE; } @Override public void onReceive(Object msg) { if (msg == Msg.GREET) { System.out.println("Hello World!"); getSender().tell(Msg.DONE, getSelf()); } else unhandled(msg); } }
  • 18.
    Sending message • tell()– Fire and forget • ask() – Send and receive
  • 19.
    Avoid Ask • https://www.safaribooksonline.com/library/view/effective- akka/9781449360061/ch02.html#_avoiding_ask •https://www.safaribooksonline.com/library/view/effective- akka/9781449360061/ch03.html#_tell_don_8217_t_ask
  • 20.
  • 21.
  • 22.
    Local application.conf LocalSys { akka{ actor { provider = "akka.remote.RemoteActorRefProvider" } remote { enabled-transports = ["akka.remote.netty.tcp"] netty.tcp { hostname = "127.0.0.1" port = 2551 } } } }
  • 23.
    Remote application.conf RemoteSys { akka{ actor { provider = "akka.remote.RemoteActorRefProvider" } remote { enabled-transports = ["akka.remote.netty.tcp"] netty.tcp { hostname = "127.0.0.1" port = 2552 } } } }
  • 24.
    Local Main public staticvoid main(String[] args) throws Exception { ActorSystem _system = ActorSystem.create("LocalNodeApp",ConfigFactory .load().getConfig("LocalSys")); ActorRef localActor = _system.actorOf(Props.create(LocalActor.class)); localActor.tell("Hello", null); Thread.sleep(5000); _system.shutdown(); }
  • 25.
    Local Actor ActorRef remoteActor; @Override publicvoid preStart() { //Get a reference to the remote actor remoteActor = getContext().actorFor( "akka.tcp://RemoteNodeApp@127.0.0.1:2552/user/remoteActor" ); } @Override public void onReceive(Object message) throws Exception { Future<Object> future = Patterns.ask(remoteActor, message.toString(), timeout); String result = (String) Await.result(future, timeout.duration()); log.info("Message received from Server -> {}", result); }
  • 26.
    Actor Path akka.<protocol>://<actorsystemname>@<hos tname>:<port>/<actor path> •http://doc.akka.io/docs/akka/2.4.1/general/addressing.html
  • 27.
    Remote Main public staticvoid main(String[] args) { final ActorSystem system = ActorSystem.create("RemoteNodeApp", ConfigFactory .load().getConfig("RemoteSys")); system.actorOf(Props.create(RemoteActor.class), "remoteActor"); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { system.shutdown(); } }); }
  • 28.
    Remote Actor @Override public voidonReceive(Object message) throws Exception { if (message instanceof String) { // Get reference to the message sender and reply back log.info("Message received -> {}", message); getSender().tell(message + " got something", null); } }
  • 29.
  • 30.
    Router Main public staticvoid main(String[] args) throws InterruptedException { ActorSystem _system = ActorSystem.create("RemoteRouteeRouterExample", ConfigFactory.load().getConfig("MyRouterExample")); Address[] addresses = new Address[]{ new Address("akka.tcp", "RemoteNodeApp", "10.211.55.6", 2552), new Address("akka.tcp", "RemoteNodeApp", "10.211.55.5", 2552) }; ActorRef router = _system.actorOf(new RemoteRouterConfig(new RoundRobinPool(5), addresses).props( Props.create(RemoteActor.class))); for (int i = 1; i <= 10; i++) { // sends randomly to actors router.tell("Hello " + Integer.toString(i), null); } _system.shutdown(); }
  • 31.
  • 32.
  • 33.
    application.conf akka { actor { provider= "akka.cluster.ClusterActorRefProvider" } remote { log-remote-lifecycle-events = off netty.tcp { hostname = "127.0.0.1" port = 0 } } cluster { seed-nodes = [ "akka.tcp://ClusterSystem@10.211.55.5:2552", "akka.tcp://ClusterSystem@10.211.55.6:2552"] auto-down-unreachable-after = 10s } }
  • 34.
  • 35.
  • 36.
    Backend Main public staticvoid main(String[] args) { // Override the configuration of the port when specified as program argument final String hostname = args.length > 0 ? args[0] : "127.0.0.1"; final String port = args.length > 1 ? args[1] : "0"; final Config config = ConfigFactory.parseString("akka.remote.netty.tcp.hostname=" + hostname). withFallback(ConfigFactory.parseString("akka.remote.netty.tcp.port=" + port)). withFallback(ConfigFactory.parseString("akka.cluster.roles = [backend]")). withFallback(ConfigFactory.load()); ActorSystem system = ActorSystem.create("ClusterSystem", config); system.actorOf(Props.create(TransformationBackend.class), "backend"); }
  • 37.
    Backend Actor -1 Cluster cluster = Cluster.get(getContext().system()); //subscribe to cluster changes, MemberUp @Override public void preStart() { cluster.subscribe(getSelf(), MemberUp.class); } //re-subscribe when restart @Override public void postStop() { cluster.unsubscribe(getSelf()); } void register(Member member) { if (member.hasRole("frontend")) getContext().actorSelection(member.address() + "/user/frontend").tell( BACKEND_REGISTRATION, getSelf()); }
  • 38.
    Backend Actor -2 @Override public void onReceive(Object message) { if (message instanceof TransformationJob) { TransformationJob job = (TransformationJob) message; getSender().tell(new TransformationResult(job.getText().toUpperCase()), getSelf()); } else if (message instanceof CurrentClusterState) { CurrentClusterState state = (CurrentClusterState) message; for (Member member : state.getMembers()) { if (member.status().equals(MemberStatus.up())) { register(member); } } } else if (message instanceof MemberUp) { MemberUp mUp = (MemberUp) message; register(mUp.member()); } else { unhandled(message); } }
  • 39.
    Frontend Main -1 final String hostname = args.length > 0 ? args[0] : "127.0.0.1"; final String port = args.length > 1 ? args[1] : "0"; final Config config = ConfigFactory.parseString("akka.remote.netty.tcp.host name=" + hostname). withFallback(ConfigFactory.parseString("akka.remote.n etty.tcp.port=" + port)). withFallback(ConfigFactory.parseString("akka.cluster. roles = [frontend]")). withFallback(ConfigFactory.load()); ActorSystem system = ActorSystem.create("ClusterSystem", config);
  • 40.
    Frontend Main -2 final ActorRef frontend = system.actorOf( Props.create(TransformationFrontend.class), "frontend"); … system.scheduler().schedule(interval, interval, new Runnable() { public void run() { Patterns.ask(frontend, new TransformationJob("hello-" + counter.incrementAndGet()), timeout).onSuccess(new OnSuccess<Object>() { public void onSuccess(Object result) { System.out.println(result); } }, ec); } }, ec);
  • 41.
    Frontend Actor -1 List<ActorRef> backends = new ArrayList<ActorRef>(); int jobCounter = 0; @Override public void onReceive(Object message) { if ((message instanceof TransformationJob) && backends.isEmpty()) { TransformationJob job = (TransformationJob) message; getSender().tell( new JobFailed("Service unavailable, try again later", job), getSender());
  • 42.
    Frontend Actor -2 } else if (message instanceof TransformationJob) { TransformationJob job = (TransformationJob) message; jobCounter++; backends.get(jobCounter % backends.size()) .forward(job, getContext()); } else if (message.equals(BACKEND_REGISTRATION)) { getContext().watch(getSender()); backends.add(getSender()); } else if (message instanceof Terminated) { Terminated terminated = (Terminated) message; backends.remove(terminated.getActor()); } else { unhandled(message); } }
  • 43.
    Run java -cp .:./* sample.cluster.transformation.TransformationBackendMa in10.211.55.5 2552 java -cp .:./* sample.cluster.transformation.TransformationBackendMa in 10.211.55.6 2552 java -cp .:./* sample.cluster.transformation.TransformationFrontendM ain 10.211.55.2 2552
  • 44.
    Best Practices • Atleast two seed nodes • Use fixed port if possible
  • 45.
    Something not mentioned •Supervision • Persistence • …
  • 46.
  • 47.
  • 48.
  • 49.
    application.conf akka { loglevel ="DEBUG" stdout-loglevel = "DEBUG" actor { provider = "akka.cluster.ClusterActorRefProvider" } remote { log-remote-lifecycle-events = off netty.tcp { hostname = "127.0.0.1" port = 0 } } cluster { // seed-nodes = [ // "akka.tcp://ClusterSystem@10.211.55.5:2552", // "akka.tcp://ClusterSystem@10.211.55.6:2552"] auto-down-unreachable-after = 10s } }
  • 50.
    reference.conf akka.cluster.seed.zookeeper { url ="10.211.55.2:2181,10.211.55.5:2181,10.211.55.6:2181" path = "/akka/cluster/seed" }
  • 51.
    Join Cluster ActorSystem system= ActorSystem.create("ClusterSystem", config); new ZookeeperClusterSeed((ExtendedActorSystem)system).join();
  • 52.
  • 53.
    factorial.conf - 1 include"application" # //#min-nr-of-members akka.cluster.min-nr-of-members = 3 # //#min-nr-of-members # //#role-min-nr-of-members akka.cluster.role { frontend.min-nr-of-members = 1 backend.min-nr-of-members = 2 } # //#role-min-nr-of-members
  • 54.
    factorial.conf - 2 #//#adaptive-router akka.actor.deployment { /factorialFrontend/factorialBackendRouter = { router = adaptive-group # metrics-selector = heap # metrics-selector = load # metrics-selector = cpu metrics-selector = mix nr-of-instances = 100 routees.paths = ["/user/factorialBackend"] cluster { enabled = on use-role = backend allow-local-routees = off } } } # //#adaptive-router
  • 55.
    Backend Main final Stringport = args.length > 0 ? args[0] : "0"; final Config config = ConfigFactory.parseString("akka.remote.netty.tcp.port=" + port). withFallback(ConfigFactory.parseString("akka.cluster.roles = [backend]")). withFallback(ConfigFactory.load("factorial")); ActorSystem system = ActorSystem.create("ClusterSystem", config); new ZookeeperClusterSeed((ExtendedActorSystem)system).join(); system.actorOf(Props.create(FactorialBackend.class), "factorialBackend"); system.actorOf(Props.create(MetricsListener.class), "metricsListener");
  • 56.
  • 57.
    Frontend Main final intupToN = 200; final Config config = ConfigFactory.parseString( "akka.cluster.roles = [frontend]").withFallback( ConfigFactory.load("factorial")); final ActorSystem system = ActorSystem.create("ClusterSystem", config); new ZookeeperClusterSeed((ExtendedActorSystem)system).join(); Cluster.get(system).registerOnMemberUp(new Runnable() { @Override public void run() { system.actorOf(Props.create(FactorialFrontend.class, upToN, true), "factorialFrontend"); } });
  • 58.
    Frontend Actor ActorRef backend= getContext().actorOf(FromConfig.getInstance().props(), "factorialBackendRouter"); … void sendJobs() { log.info("Starting batch of factorials up to [{}]", upToN); for (int n = 1; n <= upToN; n++) { backend.tell(n, getSelf()); } }
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.