SlideShare ist ein Scribd-Unternehmen logo
1 von 73
Downloaden Sie, um offline zu lesen
Akka Typed
Johan Andrén, Akka Team
Devdays Vilnius, 2018-05-23
Next generation
message driven
systems with Akka
Johan Andrén
Akka Team
Stockholm Scala User Group
@apnylle
markatta.com/codemonkey/
johan.andren@lightbend.com
Build powerful reactive, concurrent,
and distributed applications more easily
Akka
What are the tools?
Actors – simple & high performance concurrency
Cluster, Cluster tools – tools for building distributed systems
Streams – reactive streams implementation
Persistence – CQRS + Event Sourcing for Actors
HTTP – fully async streaming HTTP Server
Alpakka – Reactive Streams Integrations a’la Camel
Complete Java & Scala APIs for all features
Actors – simple & high performance concurrency
Cluster, Cluster tools – tools for building distributed systems
Streams – reactive streams implementation
Persistence – CQRS + Event Sourcing for Actors
HTTP – fully async streaming HTTP Server
Alpakka – Reactive Streams Integrations a’la Camel
Complete Java & Scala APIs for all features.
All modules ready for preview, final polish during Q2 2018
Typed
Typed
Typed
(already type-safe)
(already type-safe)
(already type-safe)
What is coming soon?
What problem are we solving?
Problems with threads
• Mutable state has to be protected everywhere it is
touched
• Atomicity isn’t always what it seems (eg. counter += 1)
• Deadlocks
• At scale
• How to know it works
• Cost (stack size, context switches, CPU cache flushes)
Services that are IO-bound
Request
Response
Actual Logic
Actual Logic
Service
Thread
Blocked
Request
Response
Services that are IO-bound
Request
Response
Actual Logic
Actual Logic
Service
Thread
Blocked
Request
Response
Services that are IO-bound
Message
Message
Actual Logic
Actual Logic
Service
Thread
Message
Message
Thread
Actor
Message
Inbox
MessageMessage
actorRef.tell(message)
Akka Actor fundamentals
• mutate state (including spawning a child actor)
• send messages to other actors
• change its behavior
Actor
Message
Inbox
MessageMessage
An Actor can…
MVS
(Minimum Viable Sample)
Na-na na-na na-na na-naSample-time!
Also known as “hello world”
import akka.actor.typed.ActorRef;
import akka.actor.typed.ActorSystem;
import akka.actor.typed.Behavior;
import akka.actor.typed.javadsl.Behaviors;
import java.io.IOException;
public class Sample1 {
static class Hello {
public final String who;
public Hello(String who) {
this.who = who;
}
}
final static Behavior<Hello> greetingBehavior =
Behaviors.receive(Hello.class)
.onMessage(Hello.class, (context, message) -> {
context.getLog().info("Hello {}!", message.who);
return Behavior.same();
}).build();
public static void main(String[] args) throws IOException {
ActorSystem<Hello> actorSystem =
ActorSystem.create(greetingBehavior, "my-system");
ActorRef<Hello> rootActor = actorSystem;
rootActor.tell(new Hello("Johan"));
rootActor.tell(new Hello("Devdays Vilnius audience"));
System.out.println("Press that any-key to terminate");
System.in.read();
actorSystem.terminate();
}
}
public class Sample1 {
static class Hello {
public final String who;
public Hello(String who) {
this.who = who;
}
}
final static Behavior<Hello> greetingBehavior =
Behaviors.receive(Hello.class)
.onMessage(Hello.class, (context, message) -> {
context.getLog().info("Hello {}!", message.who);
return Behavior.same();
}).build();
public static void main(String[] args) throws IOException {
ActorSystem<Hello> actorSystem =
ActorSystem.create(greetingBehavior, "my-system");
ActorRef<Hello> rootActor = actorSystem;
rootActor.tell(new Hello("Johan"));
public class Sample1 {
static class Hello {
public final String who;
public Hello(String who) {
this.who = who;
}
}
final static Behavior<Hello> greetingBehavior =
Behaviors.receive(Hello.class)
.onMessage(Hello.class, (context, message) -> {
context.getLog().info("Hello {}!", message.who);
return Behavior.same();
}).build();
public static void main(String[] args) throws IOException {
ActorSystem<Hello> actorSystem =
ActorSystem.create(greetingBehavior, "my-system");
ActorRef<Hello> rootActor = actorSystem;
rootActor.tell(new Hello("Johan"));
}
}
final static Behavior<Hello> greetingBehavior =
Behaviors.receive(Hello.class)
.onMessage(Hello.class, (context, message) -> {
context.getLog().info("Hello {}!", message.who);
return Behavior.same();
}).build();
public static void main(String[] args) throws IOException {
ActorSystem<Hello> actorSystem =
ActorSystem.create(greetingBehavior, "my-system");
ActorRef<Hello> rootActor = actorSystem;
rootActor.tell(new Hello("Johan"));
rootActor.tell(new Hello("Devdays Vilnius audience"));
System.out.println("Press that any-key to terminate");
System.in.read();
actorSystem.terminate();
}
}
}
}
final static Behavior<Hello> greetingBehavior =
Behaviors.receive(Hello.class)
.onMessage(Hello.class, (context, message) -> {
context.getLog().info("Hello {}!", message.who);
return Behavior.same();
}).build();
public static void main(String[] args) throws IOException {
ActorSystem<Hello> actorSystem =
ActorSystem.create(greetingBehavior, "my-system");
ActorRef<Hello> rootActor = actorSystem;
rootActor.tell(new Hello("Johan"));
rootActor.tell(new Hello("Devdays Vilnius audience"));
System.out.println("Press that any-key to terminate");
System.in.read();
actorSystem.terminate();
}
}
import akka.actor.typed.{ActorRef, ActorSystem, Behavior}
import akka.actor.typed.scaladsl.Behaviors
import scala.io.StdIn
object Sample1 {
case class Hello(who: String)
val greetingBehavior: Behavior[Hello] =
Behaviors.receive { (ctx, hello) =>
ctx.log.info(s"Hello ${hello.who}!")
Behaviors.same
}
def main(args: Array[String]): Unit = {
val system = ActorSystem(greetingBehavior, "my-system")
val rootActor: ActorRef[Hello] = system
rootActor ! Hello("Johan")
rootActor ! Hello("Devdays Vilnius audience")
println("Press the any-key to terminate")
StdIn.readLine()
system.terminate()
}
}
Let’s do another one
right away
The mystery of the changing state
🔎
interface Command {}
static class ChangeGreeting implements Command {
public final String newGreeting;
public ChangeGreeting(String newGreeting) {
this.newGreeting = newGreeting;
}
}
static class Hello implements Command {
public final String who;
public Hello(String who) {
this.who = who;
}
}
public static Behavior<Command> dynamicGreetingBehavior(String greeting) {
return Behaviors.receive(Command.class)
.onMessage(Hello.class, (context, message) -> {
context.getLog().info(greeting + " " + message.who + "!");
return Behavior.same();
}).onMessage(ChangeGreeting.class, (context, changeGreeting) ->
dynamicGreetingBehavior(changeGreeting.newGreeting)
).build();
}
public static void main(String[] args) throws IOException {
var actorSystem =
ActorSystem.create(dynamicGreetingBehavior("Hello"), "my-system");
actorSystem.tell(new Hello("Johan"));
actorSystem.tell(new ChangeGreeting("Sveiki"));
actorSystem.tell(new Hello("Devdays Vilnius audience"));
}
interface Command {}
static class ChangeGreeting implements Command {
public final String newGreeting;
public ChangeGreeting(String newGreeting) {
this.newGreeting = newGreeting;
}
}
static class Hello implements Command {
public final String who;
public Hello(String who) {
this.who = who;
}
}
public static Behavior<Command> dynamicGreetingBehavior(String greeting) {
return Behaviors.receive(Command.class)
.onMessage(Hello.class, (context, message) -> {
context.getLog().info(greeting + " " + message.who + "!");
return Behavior.same();
}).onMessage(ChangeGreeting.class, (context, changeGreeting) ->
dynamicGreetingBehavior(changeGreeting.newGreeting)
).build();
}
static class Hello implements Command {
public final String who;
public Hello(String who) {
this.who = who;
}
}
public static Behavior<Command> dynamicGreetingBehavior(String greeting) {
return Behaviors.receive(Command.class)
.onMessage(Hello.class, (context, message) -> {
context.getLog().info(greeting + " " + message.who + "!");
return Behavior.same();
}).onMessage(ChangeGreeting.class, (context, changeGreeting) ->
dynamicGreetingBehavior(changeGreeting.newGreeting)
).build();
}
public static void main(String[] args) throws IOException {
var actorSystem =
ActorSystem.create(dynamicGreetingBehavior("Hello"), "my-system");
actorSystem.tell(new Hello("Johan"));
actorSystem.tell(new ChangeGreeting("Sveiki"));
actorSystem.tell(new Hello("Devdays Vilnius audience"));
}
public static Behavior<Command> dynamicGreetingBehavior(String greeting) {
return Behaviors.receive(Command.class)
.onMessage(Hello.class, (context, message) -> {
context.getLog().info(greeting + " " + message.who + "!");
return Behavior.same();
}).onMessage(ChangeGreeting.class, (context, changeGreeting) ->
dynamicGreetingBehavior(changeGreeting.newGreeting)
).build();
}
public static void main(String[] args) throws IOException {
var actorSystem =
ActorSystem.create(dynamicGreetingBehavior("Hello"), "my-system");
actorSystem.tell(new Hello("Johan"));
actorSystem.tell(new ChangeGreeting("Sveiki"));
actorSystem.tell(new Hello("Devdays Vilnius audience"));
}
sealed trait Command
case class Hello(who: String) extends Command
case class ChangeGreeting(newGreeting: String) extends Command
def dynamicGreetingBehavior(greeting: String): Behavior[Command] =
Behaviors.receive { (ctx, message) =>
message match {
case Hello(who) =>
ctx.log.info(s"$greeting ${who}!")
Behaviors.same
case ChangeGreeting(newGreeting) =>
dynamicGreetingBehavior(newGreeting)
}
}
def main(args: Array[String]): Unit = {
val system = ActorSystem(dynamicGreetingBehavior("Hello"), "my-system")
system ! Hello("Johan")
system ! ChangeGreeting("Sveiki")
system ! Hello("Devdays Vilnius audience")
}
But I don’t like it
(the FP style, that is)
static class MutableGreetingBehavior extends MutableBehavior<Command> {
private final ActorContext<Command> context;
private String greeting;
public MutableGreetingBehavior(String initialGreeting, ActorContext<Command> context) {
this.context = context;
greeting = initialGreeting;
}
@Override
public Behaviors.Receive<Command> createReceive() {
return receiveBuilder()
.onMessage(Hello.class, this::onHello)
.onMessage(ChangeGreeting.class, this::onChangeGreeting)
.build();
}
private Behavior<Command> onHello(Hello hello) {
context.getLog().info(greeting + " " + hello.who + "!");
return Behaviors.same();
}
private Behavior<Command> onChangeGreeting(ChangeGreeting changeGreeting) {
greeting = changeGreeting.newGreeting;
return Behaviors.same();
}
}
static class MutableGreetingBehavior extends MutableBehavior<Command> {
private final ActorContext<Command> context;
private String greeting;
public MutableGreetingBehavior(String initialGreeting, ActorContext<Co
this.context = context;
greeting = initialGreeting;
}
@Override
public Behaviors.Receive<Command> createReceive() {
return receiveBuilder()
.onMessage(Hello.class, this::onHello)
.onMessage(ChangeGreeting.class, this::onChangeGreeting)
.build();
}
private Behavior<Command> onHello(Hello hello) {
context.getLog().info(greeting + " " + hello.who + "!");
return Behaviors.same();
}
static class MutableGreetingBehavior extends MutableBehavior<Command> {
private final ActorContext<Command> context;
private String greeting;
public MutableGreetingBehavior(String initialGreeting, ActorContext<Co
this.context = context;
greeting = initialGreeting;
}
@Override
public Behaviors.Receive<Command> createReceive() {
return receiveBuilder()
.onMessage(Hello.class, this::onHello)
.onMessage(ChangeGreeting.class, this::onChangeGreeting)
.build();
}
private Behavior<Command> onHello(Hello hello) {
context.getLog().info(greeting + " " + hello.who + "!");
return Behaviors.same();
}
static class MutableGreetingBehavior extends MutableBehavior<Command> {
private final ActorContext<Command> context;
private String greeting;
public MutableGreetingBehavior(String initialGreeting, ActorContext<Co
this.context = context;
greeting = initialGreeting;
}
@Override
public Behaviors.Receive<Command> createReceive() {
return receiveBuilder()
.onMessage(Hello.class, this::onHello)
.onMessage(ChangeGreeting.class, this::onChangeGreeting)
.build();
}
private Behavior<Command> onHello(Hello hello) {
context.getLog().info(greeting + " " + hello.who + "!");
return Behaviors.same();
}
greeting = initialGreeting;
}
@Override
public Behaviors.Receive<Command> createReceive() {
return receiveBuilder()
.onMessage(Hello.class, this::onHello)
.onMessage(ChangeGreeting.class, this::onChangeGreeting)
.build();
}
private Behavior<Command> onHello(Hello hello) {
context.getLog().info(greeting + " " + hello.who + "!");
return Behaviors.same();
}
private Behavior<Command> onChangeGreeting(ChangeGreeting changeGreeti
greeting = changeGreeting.newGreeting;
return Behaviors.same();
}
}
public static void main(String[] args) {
var system = ActorSystem.<Command>create(
Behaviors.setup((context) ->
new MutableGreetingBehavior("Hello", context)),
"my-system"
);
system.tell(new Hello("Johan"));
system.tell(new ChangeGreeting("Sveiki"));
system.tell(new Hello("Devdays Vilnius audience"));
}
• Discoverability, how are things related
• More compile time type-safety, less runtime debugging
Types helps productivity!
(and results in more reliable systems in production)
The need for strong/strict typing
“Sending the wrong message to an actor is
actually quite uncommon”
– Myself, last week
Burglar Alarm
• enabled/disabled with a pin code
• accepts notifications about “activity”
• if enabled on activity, sound the alarm
“Realistic” Example
DIY
interface AlarmMessage {}
static class EnableAlarm implements AlarmMessage {
public final String pinCode;
public EnableAlarm(String pinCode) {
this.pinCode = pinCode;
}
}
static class DisableAlarm implements AlarmMessage {
public final String pinCode;
public DisableAlarm(String pinCode) {
this.pinCode = pinCode;
}
}
static class ActivityEvent implements AlarmMessage { }
public static Behavior<AlarmMessage> enabledAlarm(String pinCode) {
return Behaviors.receive(AlarmMessage.class)
.onMessage(
DisableAlarm.class,
// predicate
(disable) -> disable.pinCode.equals(pinCode),
(context, message) -> {
context.getLog().info("Correct pin entered, disabling alarm");
return disabledAlarm(pinCode);
}
).onMessage(ActivityEvent.class, (context, activityEvent) -> {
context.getLog().warning("EOEOEOEOEOE ALARM ALARM!!!");
return Behaviors.same();
}).build();
}
public static Behavior<AlarmMessage> disabledAlarm(String pinCode) {
return Behaviors.receive(AlarmMessage.class)
.onMessage(EnableAlarm.class,
// predicate
(enable) -> enable.pinCode.equals(pinCode),
(context, message) -> {
context.getLog().info("Correct pin entered, enabling alarm");
return enabledAlarm(pinCode);
}
).build();
}
public static void main(String[] args) {
var system = ActorSystem.create(enabledAlarm("0000"), "my-system");
system.tell(new ActivityEvent());
system.tell(new DisableAlarm("1234"));
system.tell(new ActivityEvent());
system.tell(new DisableAlarm("0000"));
system.tell(new ActivityEvent());
system.tell(new EnableAlarm("0000"));
}
sealed trait AlarmMessage
case class EnableAlarm(pinCode: String) extends AlarmMessage
case class DisableAlarm(pinCode: String) extends AlarmMessage
case object ActivityEvent extends AlarmMessage
def enabledAlarm(pinCode: String): Behavior[AlarmMessage] =
Behaviors.receive { (context, message) =>
message match {
case ActivityEvent =>
context.log.warning("EOEOEOEOEOE ALARM ALARM!!!")
Behaviors.same
case DisableAlarm(`pinCode`) =>
context.log.info("Correct pin entered, disabling alarm");
disabledAlarm(pinCode)
case _ => Behaviors.unhandled
}
}
def disabledAlarm(pinCode: String): Behavior[AlarmMessage] =
Behaviors.receivePartial {
case (context, EnableAlarm(`pinCode`)) =>
context.log.info("Correct pin entered, enabling alarm")
enabledAlarm(pinCode)
}
def main(args: Array[String]): Unit = {
val system = ActorSystem.create(enabledAlarm("0000"), "my-system")
system.tell(ActivityEvent)
system.tell(DisableAlarm("1234"))
system.tell(ActivityEvent)
system.tell(DisableAlarm("0000"))
system.tell(ActivityEvent)
system.tell(EnableAlarm("0000"))
system.tell(ActivityEvent)
}
Request-response with other actors
• In untyped actors the sender was
auto-magically available
• In Akka Typed the recipient of
response has to be encoded in
message (why?)
Request-response with other actors
Actor<ProtocolA> Actor<ProtocolB>
RequestForB
ActorRef<ResponseFromB>
ResponseFromBProtocolA
?
Request-response with other actors
Actor<ProtocolA> Actor<ProtocolB>
RequestForB
ActorRef<ResponseFromB>
ResponseFromBProtocolA
ResponseFromB -> ProtocolA
?
One off with Ask
context.ask(
ResponseFromB.class,
actorB,
Timeout.create(Duration.ofSeconds(5)),
(ActorRef<ResponseFromB> respondTo) -> new RequestForB(respondTo),
(ResponseFromB res, Throwable failure) -> {
if (res != null) return new ProtocolAMessage(res);
else throw new RuntimeException("Request failed", failure);
}
);
Long live the adapter
ActorRef<ResponseFromB> adapter = context.messageAdapter(
ResponseFromB.class,
(responseFromB) -> new ProtocolAMessage(responseFromB)
);
actorB.tell(new RequestForB(adapter));
Keeping parts of the protocol to ourselves
ActorRef<ProtocolA> actorRef = …
ActorRef<SubProtocolA> moreNarrowActorRef = actorRef.narrow();
ProtocolA
SubProtocolA SubProtocolA2
Distributed Systems
–Leslie Lamport
”A distributed system is one in which the failure
of a computer you didn't even know existed can
render your own computer unusable”
Why is it so hard?
Reliability: power failure, old network 

equipment, network congestion, coffee in router, 

rodents, that guy in the IT dept., DDOS attacks…
Latency: loopback vs local net vs shared congested local net
vs internet
Bandwidth: again loopback vs local vs shared local vs
internet
The Joys of Computer Networks:
Partial Failure
✂
Node 1 Node 2
request
response
Partial Failure
✂
Node 1 Node 2
request 💥
Partial Failure
✂
Node 1 Node 2
request
💥
Partial Failure
✂
Node 1 Node 2
request
response
💥
Why do it, if it is so hard?
Data or processing doesn’t fit a single machine

Many objects, that should be kept in memory. Many not so
powerful servers can be cheaper than a supercomputer.
Elasticity

Being able to scale in (less servers) and out (more servers)
depending on load. Not paying for servers unless you need them.
Resilience

Building systems that will keep working in the face of failures or
degrade gracefully.
Actor Model vs Network
Interaction already modelled as immutable messages

Data travels over the network in packages, changes has to be explicitly sent
back.
At most once

Data reaches a node on the other side at most once, but can be lost, already
part of model!
A recipient of a message can reply directly to sender

Regardless if there were intermediate recipients of the message
Messages not limited to request response

Messages can flow in either direction when two systems are connected.
Local
ActorSystem
Message
Message
Actor
Actor
Actor
JVM 2
JVM 1
Distributed
ActorSystem
ActorSystem
Message
Message
Actor
Actor
Actor
Akka Cluster + Akka Typed
ActorSystem ActorSystem
ActorSystem
Receptionist
Typed Receptionist
Receptionist
Receptionist
ActorRef<AlarmMessage>
Sensor-Actor
Subscribe(key, actorRef)
Receptionist
Typed Receptionist
Receptionist
Receptionist
Register(Key<AlarmMessage>,
ActorRef<AlarmMessage>)
ActorRef<AlarmMessage>
Sensor-Actor
Receptionist
Typed Receptionist
Receptionist
Receptionist
ActorRef[AlarmMessage]
Sensor-Actor
Listing(key, actorRefs)
Receptionist
Typed Receptionist
Receptionist
Receptionist
ActorRef<AlarmMessage>
Sensor-Actor
ActorRef<AlarmMessage>
AlarmMessage
Distributed Burglar Alarm
• we can have any number of
nodes
• a sensor on any node can
report activity to the alarm
Example
DYI
Distributed
static final ServiceKey<ActivityEvent> serviceKey =
ServiceKey.create(ActivityEvent.class, "alarm");
interface AlarmMessage extends Serializable {}
static class EnableAlarm implements AlarmMessage {
public final String pinCode;
public EnableAlarm(String pinCode) {
this.pinCode = pinCode;
}
}
static class DisableAlarm implements AlarmMessage {
public final String pinCode;
public DisableAlarm(String pinCode) {
this.pinCode = pinCode;
}
}
static class ActivityEvent implements AlarmMessage { }
static final ServiceKey<ActivityEvent> serviceKey =
ServiceKey.create(ActivityEvent.class, "alarm");
interface AlarmMessage extends Serializable {}
static class EnableAlarm implements AlarmMessage {
public final String pinCode;
public EnableAlarm(String pinCode) {
this.pinCode = pinCode;
}
}
static class DisableAlarm implements AlarmMessage {
public final String pinCode;
public DisableAlarm(String pinCode) {
this.pinCode = pinCode;
}
}
static class ActivityEvent implements AlarmMessage { }
public static Behavior<AlarmMessage> alarm(String pinCode) {
return Behaviors.setup((context) -> {
ActorRef<Receptionist.Command> receptionist =
context.getSystem().receptionist();
receptionist.tell(
Receptionist.register(serviceKey, context.getSelf().narrow()));
return enabledAlarm(pinCode);
});
}
public static class SensorBehavior extends MutableBehavior<TriggerCommand> {
private final ActorContext<TriggerCommand> context;
private Set<ActorRef<ActivityEvent>> alarms = Collections.EMPTY_SET;
public SensorBehavior(ActorContext<TriggerCommand> context) {
this.context = context;
// we need to transform the messages from the receptionist protocol
// into our own protocol:
ActorRef<Receptionist.Listing> adapter = context.messageAdapter(
Receptionist.Listing.class,
(listing) -> new AlarmActorUpdate(listing.getServiceInstances(serviceKey))
);
ActorRef<Receptionist.Command> receptionist = context.getSystem().receptionist();
receptionist.tell(Receptionist.subscribe(serviceKey, adapter));
}
@Override
public Behaviors.Receive<TriggerCommand> createReceive() {
return receiveBuilder()
.onMessage(TriggerSensor.class, this::onTrigger)
.onMessage(AlarmActorUpdate.class, this::onAlarmActorUpdate)
.build();
}
private Behavior<TriggerCommand> onTrigger(TriggerSensor trigger) {
final ActivityEvent activityEvent = new ActivityEvent();
if (alarms.isEmpty()) context.getLog().warning("Saw trigger but no alarms known yet");
alarms.forEach((alarm) ->
alarm.tell(activityEvent)
);
return Behaviors.same();
}
private Behavior<TriggerCommand> onAlarmActorUpdate(AlarmActorUpdate update) {
context.getLog().info("Got alarm actor list update");
alarms = update.alarms;
return Behaviors.same();
}
}
public static class SensorBehavior extends MutableBehavior<TriggerCommand> {
private final ActorContext<TriggerCommand> context;
private Set<ActorRef<ActivityEvent>> alarms = Collections.EMPTY_SET;
public SensorBehavior(ActorContext<TriggerCommand> context) {
this.context = context;
// we need to transform the messages from the receptionist protocol
// into our own protocol:
ActorRef<Receptionist.Listing> adapter = context.messageAdapter(
Receptionist.Listing.class,
(listing) -> new AlarmActorUpdate(listing.getServiceInstances(serviceKey))
);
ActorRef<Receptionist.Command> receptionist = context.getSystem().receptionist();
receptionist.tell(Receptionist.subscribe(serviceKey, adapter));
}
@Override
public Behaviors.Receive<TriggerCommand> createReceive() {
return receiveBuilder()
.onMessage(TriggerSensor.class, this::onTrigger)
.onMessage(AlarmActorUpdate.class, this::onAlarmActorUpdate)
.build();
}
private Behavior<TriggerCommand> onTrigger(TriggerSensor trigger) {
final ActivityEvent activityEvent = new ActivityEvent();
if (alarms.isEmpty()) context.getLog().warning("Saw trigger but no alarms known yet");
);
ActorRef<Receptionist.Command> receptionist = context.getSystem().receptionist();
receptionist.tell(Receptionist.subscribe(serviceKey, adapter));
}
@Override
public Behaviors.Receive<TriggerCommand> createReceive() {
return receiveBuilder()
.onMessage(TriggerSensor.class, this::onTrigger)
.onMessage(AlarmActorUpdate.class, this::onAlarmActorUpdate)
.build();
}
private Behavior<TriggerCommand> onTrigger(TriggerSensor trigger) {
final ActivityEvent activityEvent = new ActivityEvent();
if (alarms.isEmpty()) context.getLog().warning("Saw trigger but no alarms known yet");
alarms.forEach((alarm) ->
alarm.tell(activityEvent)
);
return Behaviors.same();
}
private Behavior<TriggerCommand> onAlarmActorUpdate(AlarmActorUpdate update) {
context.getLog().info("Got alarm actor list update");
alarms = update.alarms;
return Behaviors.same();
}
}
public static void main(String[] args) throws Exception {
ActorSystem<AlarmMessage> system1 =
ActorSystem.create(alarm("0000"), "my-cluster");
ActorSystem<TriggerCommand> system2 =
ActorSystem.create(sensorBehavior(), "my-cluster");
ActorSystem<TriggerCommand> system3 =
ActorSystem.create(sensorBehavior(), "my-cluster");
// first join the first node to itself to form a cluster
Cluster node1 = Cluster.get(system1);
node1.manager().tell(Join.create(node1.selfMember().address()));
// then have node 2 and 3 join that cluster
Cluster node2 = Cluster.get(system2);
node2.manager().tell(Join.create(node1.selfMember().address()));
Cluster node3 = Cluster.get(system3);
node3.manager().tell(Join.create(node1.selfMember().address()));
Scanner in = new Scanner(System.in);
while (true) {
// then have node 2 and 3 join that cluster
Cluster node2 = Cluster.get(system2);
node2.manager().tell(Join.create(node1.selfMember().address()));
Cluster node3 = Cluster.get(system3);
node3.manager().tell(Join.create(node1.selfMember().address()));
Scanner in = new Scanner(System.in);
while (true) {
try {
System.out.println("Enter 2 or 3 to trigger activity on that node");
int chosenNode = Integer.parseInt(in.next());
System.out.println("Triggering sensor on node " + chosenNode);
if (chosenNode == 2) system2.tell(new TriggerSensor());
else if (chosenNode == 3) system3.tell(new TriggerSensor());
} catch (Exception ex) {
// we don't care, loop!
}
}
}
Summary
• On message - message another actor, change
state or behavior
• Types gives better guardrails and makes
understanding the system easier
• We can use the same abstraction for local and
distributed
GitHub repo with all samples in this talk
bit.ly/2LnOU4L
Akka typed docs
doc.akka.io/docs/akka/2.5/typed/index.html
More resources
blog.akka.io - news and articles
discuss.akka.io - forums
developer.lightbend.com - samples
github.com/akka/akka - sources and getting involved
Further reading
Questions?
GitHub repo with all samples in this talk
bit.ly/2LnOU4L
http://akka.io
@apnylle
johan.andren@lightbend.com
Thanks for listening!

Weitere ähnliche Inhalte

Was ist angesagt?

Akka Actor presentation
Akka Actor presentationAkka Actor presentation
Akka Actor presentationGene Chang
 
Building reactive distributed systems with Akka
Building reactive distributed systems with Akka Building reactive distributed systems with Akka
Building reactive distributed systems with Akka Johan Andrén
 
Akka streams - Umeå java usergroup
Akka streams - Umeå java usergroupAkka streams - Umeå java usergroup
Akka streams - Umeå java usergroupJohan Andrén
 
Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams
Fresh from the Oven (04.2015): Experimental Akka Typed and Akka StreamsFresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams
Fresh from the Oven (04.2015): Experimental Akka Typed and Akka StreamsKonrad Malawski
 
Developing distributed applications with Akka and Akka Cluster
Developing distributed applications with Akka and Akka ClusterDeveloping distributed applications with Akka and Akka Cluster
Developing distributed applications with Akka and Akka ClusterKonstantin Tsykulenko
 
Akka Cluster in Java - JCConf 2015
Akka Cluster in Java - JCConf 2015Akka Cluster in Java - JCConf 2015
Akka Cluster in Java - JCConf 2015Jiayun Zhou
 
Reactive integrations with Akka Streams
Reactive integrations with Akka StreamsReactive integrations with Akka Streams
Reactive integrations with Akka StreamsKonrad Malawski
 
Async - react, don't wait - PingConf
Async - react, don't wait - PingConfAsync - react, don't wait - PingConf
Async - react, don't wait - PingConfJohan Andrén
 
Scala usergroup stockholm - reactive integrations with akka streams
Scala usergroup stockholm - reactive integrations with akka streamsScala usergroup stockholm - reactive integrations with akka streams
Scala usergroup stockholm - reactive integrations with akka streamsJohan Andrén
 
Introduction to rx java for android
Introduction to rx java for androidIntroduction to rx java for android
Introduction to rx java for androidEsa Firman
 
Reactive Streams / Akka Streams - GeeCON Prague 2014
Reactive Streams / Akka Streams - GeeCON Prague 2014Reactive Streams / Akka Streams - GeeCON Prague 2014
Reactive Streams / Akka Streams - GeeCON Prague 2014Konrad Malawski
 
Advanced akka features
Advanced akka featuresAdvanced akka features
Advanced akka featuresGrzegorz Duda
 
Samuele Resca - REACTIVE PROGRAMMING, DAMN. IT IS NOT ABOUT REACTJS - Codemot...
Samuele Resca - REACTIVE PROGRAMMING, DAMN. IT IS NOT ABOUT REACTJS - Codemot...Samuele Resca - REACTIVE PROGRAMMING, DAMN. IT IS NOT ABOUT REACTJS - Codemot...
Samuele Resca - REACTIVE PROGRAMMING, DAMN. IT IS NOT ABOUT REACTJS - Codemot...Codemotion
 
Sane Sharding with Akka Cluster
Sane Sharding with Akka ClusterSane Sharding with Akka Cluster
Sane Sharding with Akka Clustermiciek
 
Mario Fusco - Reactive programming in Java - Codemotion Milan 2017
Mario Fusco - Reactive programming in Java - Codemotion Milan 2017Mario Fusco - Reactive programming in Java - Codemotion Milan 2017
Mario Fusco - Reactive programming in Java - Codemotion Milan 2017Codemotion
 
End to End Akka Streams / Reactive Streams - from Business to Socket
End to End Akka Streams / Reactive Streams - from Business to SocketEnd to End Akka Streams / Reactive Streams - from Business to Socket
End to End Akka Streams / Reactive Streams - from Business to SocketKonrad Malawski
 
Introduction to Akka - Atlanta Java Users Group
Introduction to Akka - Atlanta Java Users GroupIntroduction to Akka - Atlanta Java Users Group
Introduction to Akka - Atlanta Java Users GroupRoy Russo
 
Reactive programming with RxJava
Reactive programming with RxJavaReactive programming with RxJava
Reactive programming with RxJavaJobaer Chowdhury
 
Akka lsug skills matter
Akka lsug skills matterAkka lsug skills matter
Akka lsug skills matterSkills Matter
 

Was ist angesagt? (20)

Akka Actor presentation
Akka Actor presentationAkka Actor presentation
Akka Actor presentation
 
Building reactive distributed systems with Akka
Building reactive distributed systems with Akka Building reactive distributed systems with Akka
Building reactive distributed systems with Akka
 
Akka streams - Umeå java usergroup
Akka streams - Umeå java usergroupAkka streams - Umeå java usergroup
Akka streams - Umeå java usergroup
 
Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams
Fresh from the Oven (04.2015): Experimental Akka Typed and Akka StreamsFresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams
Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams
 
Developing distributed applications with Akka and Akka Cluster
Developing distributed applications with Akka and Akka ClusterDeveloping distributed applications with Akka and Akka Cluster
Developing distributed applications with Akka and Akka Cluster
 
Akka Cluster in Java - JCConf 2015
Akka Cluster in Java - JCConf 2015Akka Cluster in Java - JCConf 2015
Akka Cluster in Java - JCConf 2015
 
Reactive integrations with Akka Streams
Reactive integrations with Akka StreamsReactive integrations with Akka Streams
Reactive integrations with Akka Streams
 
Async - react, don't wait - PingConf
Async - react, don't wait - PingConfAsync - react, don't wait - PingConf
Async - react, don't wait - PingConf
 
Scala usergroup stockholm - reactive integrations with akka streams
Scala usergroup stockholm - reactive integrations with akka streamsScala usergroup stockholm - reactive integrations with akka streams
Scala usergroup stockholm - reactive integrations with akka streams
 
Introduction to rx java for android
Introduction to rx java for androidIntroduction to rx java for android
Introduction to rx java for android
 
Reactive Streams / Akka Streams - GeeCON Prague 2014
Reactive Streams / Akka Streams - GeeCON Prague 2014Reactive Streams / Akka Streams - GeeCON Prague 2014
Reactive Streams / Akka Streams - GeeCON Prague 2014
 
Advanced akka features
Advanced akka featuresAdvanced akka features
Advanced akka features
 
Actor Model Akka Framework
Actor Model Akka FrameworkActor Model Akka Framework
Actor Model Akka Framework
 
Samuele Resca - REACTIVE PROGRAMMING, DAMN. IT IS NOT ABOUT REACTJS - Codemot...
Samuele Resca - REACTIVE PROGRAMMING, DAMN. IT IS NOT ABOUT REACTJS - Codemot...Samuele Resca - REACTIVE PROGRAMMING, DAMN. IT IS NOT ABOUT REACTJS - Codemot...
Samuele Resca - REACTIVE PROGRAMMING, DAMN. IT IS NOT ABOUT REACTJS - Codemot...
 
Sane Sharding with Akka Cluster
Sane Sharding with Akka ClusterSane Sharding with Akka Cluster
Sane Sharding with Akka Cluster
 
Mario Fusco - Reactive programming in Java - Codemotion Milan 2017
Mario Fusco - Reactive programming in Java - Codemotion Milan 2017Mario Fusco - Reactive programming in Java - Codemotion Milan 2017
Mario Fusco - Reactive programming in Java - Codemotion Milan 2017
 
End to End Akka Streams / Reactive Streams - from Business to Socket
End to End Akka Streams / Reactive Streams - from Business to SocketEnd to End Akka Streams / Reactive Streams - from Business to Socket
End to End Akka Streams / Reactive Streams - from Business to Socket
 
Introduction to Akka - Atlanta Java Users Group
Introduction to Akka - Atlanta Java Users GroupIntroduction to Akka - Atlanta Java Users Group
Introduction to Akka - Atlanta Java Users Group
 
Reactive programming with RxJava
Reactive programming with RxJavaReactive programming with RxJava
Reactive programming with RxJava
 
Akka lsug skills matter
Akka lsug skills matterAkka lsug skills matter
Akka lsug skills matter
 

Ähnlich wie Next generation message driven systems with Akka

Concurrency and scalability with akka
Concurrency and scalability  with akkaConcurrency and scalability  with akka
Concurrency and scalability with akkaBardia Heydari
 
Painless Persistence with Realm
Painless Persistence with RealmPainless Persistence with Realm
Painless Persistence with RealmChristian Melchior
 
Testing in android
Testing in androidTesting in android
Testing in androidjtrindade
 
Testing basics for developers
Testing basics for developersTesting basics for developers
Testing basics for developersAnton Udovychenko
 
Productive Programming in Java 8 - with Lambdas and Streams
Productive Programming in Java 8 - with Lambdas and Streams Productive Programming in Java 8 - with Lambdas and Streams
Productive Programming in Java 8 - with Lambdas and Streams Ganesh Samarthyam
 
Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Sven Efftinge
 
Making Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMMaking Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMRafael Winterhalter
 
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureScalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureFDConf
 
The definitive guide to java agents
The definitive guide to java agentsThe definitive guide to java agents
The definitive guide to java agentsRafael Winterhalter
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!DataArt
 
Reactive programming on Android
Reactive programming on AndroidReactive programming on Android
Reactive programming on AndroidTomáš Kypta
 
Hacking JavaFX with Groovy, Clojure, Scala, and Visage: Stephen Chin
Hacking JavaFX with Groovy, Clojure, Scala, and Visage: Stephen ChinHacking JavaFX with Groovy, Clojure, Scala, and Visage: Stephen Chin
Hacking JavaFX with Groovy, Clojure, Scala, and Visage: Stephen Chinjaxconf
 
Reactive programming every day
Reactive programming every dayReactive programming every day
Reactive programming every dayVadym Khondar
 
Groovy & Grails: Scripting for Modern Web Applications
Groovy & Grails: Scripting for Modern Web ApplicationsGroovy & Grails: Scripting for Modern Web Applications
Groovy & Grails: Scripting for Modern Web Applicationsrohitnayak
 
Laurens Van Den Oever Xopus Presentation
Laurens Van Den Oever Xopus PresentationLaurens Van Den Oever Xopus Presentation
Laurens Van Den Oever Xopus PresentationAjax Experience 2009
 
jQuery for beginners
jQuery for beginnersjQuery for beginners
jQuery for beginnersDivakar Gu
 

Ähnlich wie Next generation message driven systems with Akka (20)

Concurrency and scalability with akka
Concurrency and scalability  with akkaConcurrency and scalability  with akka
Concurrency and scalability with akka
 
Painless Persistence with Realm
Painless Persistence with RealmPainless Persistence with Realm
Painless Persistence with Realm
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011
 
Lambda Functions in Java 8
Lambda Functions in Java 8Lambda Functions in Java 8
Lambda Functions in Java 8
 
Testing in android
Testing in androidTesting in android
Testing in android
 
Testing basics for developers
Testing basics for developersTesting basics for developers
Testing basics for developers
 
Productive Programming in Java 8 - with Lambdas and Streams
Productive Programming in Java 8 - with Lambdas and Streams Productive Programming in Java 8 - with Lambdas and Streams
Productive Programming in Java 8 - with Lambdas and Streams
 
Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]
 
IKH331-07-java-rmi
IKH331-07-java-rmiIKH331-07-java-rmi
IKH331-07-java-rmi
 
Java 5 and 6 New Features
Java 5 and 6 New FeaturesJava 5 and 6 New Features
Java 5 and 6 New Features
 
Making Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMMaking Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVM
 
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureScalable Angular 2 Application Architecture
Scalable Angular 2 Application Architecture
 
The definitive guide to java agents
The definitive guide to java agentsThe definitive guide to java agents
The definitive guide to java agents
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!
 
Reactive programming on Android
Reactive programming on AndroidReactive programming on Android
Reactive programming on Android
 
Hacking JavaFX with Groovy, Clojure, Scala, and Visage: Stephen Chin
Hacking JavaFX with Groovy, Clojure, Scala, and Visage: Stephen ChinHacking JavaFX with Groovy, Clojure, Scala, and Visage: Stephen Chin
Hacking JavaFX with Groovy, Clojure, Scala, and Visage: Stephen Chin
 
Reactive programming every day
Reactive programming every dayReactive programming every day
Reactive programming every day
 
Groovy & Grails: Scripting for Modern Web Applications
Groovy & Grails: Scripting for Modern Web ApplicationsGroovy & Grails: Scripting for Modern Web Applications
Groovy & Grails: Scripting for Modern Web Applications
 
Laurens Van Den Oever Xopus Presentation
Laurens Van Den Oever Xopus PresentationLaurens Van Den Oever Xopus Presentation
Laurens Van Den Oever Xopus Presentation
 
jQuery for beginners
jQuery for beginnersjQuery for beginners
jQuery for beginners
 

Mehr von Johan Andrén

Asynchronous stream processing with Akka Streams
Asynchronous stream processing with Akka StreamsAsynchronous stream processing with Akka Streams
Asynchronous stream processing with Akka StreamsJohan Andrén
 
VJUG24 - Reactive Integrations with Akka Streams
VJUG24  - Reactive Integrations with Akka StreamsVJUG24  - Reactive Integrations with Akka Streams
VJUG24 - Reactive Integrations with Akka StreamsJohan Andrén
 
Introduction to akka actors with java 8
Introduction to akka actors with java 8Introduction to akka actors with java 8
Introduction to akka actors with java 8Johan Andrén
 
Scala frukostseminarium
Scala frukostseminariumScala frukostseminarium
Scala frukostseminariumJohan Andrén
 
Introduction to Akka
Introduction to AkkaIntroduction to Akka
Introduction to AkkaJohan Andrén
 
Async – react, don't wait
Async – react, don't waitAsync – react, don't wait
Async – react, don't waitJohan Andrén
 
Akka frukostseminarium
Akka   frukostseminariumAkka   frukostseminarium
Akka frukostseminariumJohan Andrén
 
Macros and reflection in scala 2.10
Macros and reflection in scala 2.10Macros and reflection in scala 2.10
Macros and reflection in scala 2.10Johan Andrén
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to ScalaJohan Andrén
 

Mehr von Johan Andrén (10)

Asynchronous stream processing with Akka Streams
Asynchronous stream processing with Akka StreamsAsynchronous stream processing with Akka Streams
Asynchronous stream processing with Akka Streams
 
VJUG24 - Reactive Integrations with Akka Streams
VJUG24  - Reactive Integrations with Akka StreamsVJUG24  - Reactive Integrations with Akka Streams
VJUG24 - Reactive Integrations with Akka Streams
 
Introduction to akka actors with java 8
Introduction to akka actors with java 8Introduction to akka actors with java 8
Introduction to akka actors with java 8
 
Scala frukostseminarium
Scala frukostseminariumScala frukostseminarium
Scala frukostseminarium
 
Introduction to Akka
Introduction to AkkaIntroduction to Akka
Introduction to Akka
 
Async – react, don't wait
Async – react, don't waitAsync – react, don't wait
Async – react, don't wait
 
Akka frukostseminarium
Akka   frukostseminariumAkka   frukostseminarium
Akka frukostseminarium
 
Macros and reflection in scala 2.10
Macros and reflection in scala 2.10Macros and reflection in scala 2.10
Macros and reflection in scala 2.10
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
 
Duchess scala-2012
Duchess scala-2012Duchess scala-2012
Duchess scala-2012
 

Kürzlich hochgeladen

How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rick Flair
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 

Kürzlich hochgeladen (20)

How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 

Next generation message driven systems with Akka

  • 1. Akka Typed Johan Andrén, Akka Team Devdays Vilnius, 2018-05-23 Next generation message driven systems with Akka
  • 2. Johan Andrén Akka Team Stockholm Scala User Group @apnylle markatta.com/codemonkey/ johan.andren@lightbend.com
  • 3. Build powerful reactive, concurrent, and distributed applications more easily Akka
  • 4. What are the tools? Actors – simple & high performance concurrency Cluster, Cluster tools – tools for building distributed systems Streams – reactive streams implementation Persistence – CQRS + Event Sourcing for Actors HTTP – fully async streaming HTTP Server Alpakka – Reactive Streams Integrations a’la Camel Complete Java & Scala APIs for all features
  • 5. Actors – simple & high performance concurrency Cluster, Cluster tools – tools for building distributed systems Streams – reactive streams implementation Persistence – CQRS + Event Sourcing for Actors HTTP – fully async streaming HTTP Server Alpakka – Reactive Streams Integrations a’la Camel Complete Java & Scala APIs for all features. All modules ready for preview, final polish during Q2 2018 Typed Typed Typed (already type-safe) (already type-safe) (already type-safe) What is coming soon?
  • 6. What problem are we solving?
  • 7. Problems with threads • Mutable state has to be protected everywhere it is touched • Atomicity isn’t always what it seems (eg. counter += 1) • Deadlocks • At scale • How to know it works • Cost (stack size, context switches, CPU cache flushes)
  • 8. Services that are IO-bound Request Response Actual Logic Actual Logic Service Thread Blocked Request Response
  • 9. Services that are IO-bound Request Response Actual Logic Actual Logic Service Thread Blocked Request Response
  • 10. Services that are IO-bound Message Message Actual Logic Actual Logic Service Thread Message Message Thread
  • 12. • mutate state (including spawning a child actor) • send messages to other actors • change its behavior Actor Message Inbox MessageMessage An Actor can…
  • 13. MVS (Minimum Viable Sample) Na-na na-na na-na na-naSample-time! Also known as “hello world”
  • 14. import akka.actor.typed.ActorRef; import akka.actor.typed.ActorSystem; import akka.actor.typed.Behavior; import akka.actor.typed.javadsl.Behaviors; import java.io.IOException; public class Sample1 { static class Hello { public final String who; public Hello(String who) { this.who = who; } } final static Behavior<Hello> greetingBehavior = Behaviors.receive(Hello.class) .onMessage(Hello.class, (context, message) -> { context.getLog().info("Hello {}!", message.who); return Behavior.same(); }).build(); public static void main(String[] args) throws IOException { ActorSystem<Hello> actorSystem = ActorSystem.create(greetingBehavior, "my-system"); ActorRef<Hello> rootActor = actorSystem; rootActor.tell(new Hello("Johan")); rootActor.tell(new Hello("Devdays Vilnius audience")); System.out.println("Press that any-key to terminate"); System.in.read(); actorSystem.terminate(); } }
  • 15. public class Sample1 { static class Hello { public final String who; public Hello(String who) { this.who = who; } } final static Behavior<Hello> greetingBehavior = Behaviors.receive(Hello.class) .onMessage(Hello.class, (context, message) -> { context.getLog().info("Hello {}!", message.who); return Behavior.same(); }).build(); public static void main(String[] args) throws IOException { ActorSystem<Hello> actorSystem = ActorSystem.create(greetingBehavior, "my-system"); ActorRef<Hello> rootActor = actorSystem; rootActor.tell(new Hello("Johan"));
  • 16. public class Sample1 { static class Hello { public final String who; public Hello(String who) { this.who = who; } } final static Behavior<Hello> greetingBehavior = Behaviors.receive(Hello.class) .onMessage(Hello.class, (context, message) -> { context.getLog().info("Hello {}!", message.who); return Behavior.same(); }).build(); public static void main(String[] args) throws IOException { ActorSystem<Hello> actorSystem = ActorSystem.create(greetingBehavior, "my-system"); ActorRef<Hello> rootActor = actorSystem; rootActor.tell(new Hello("Johan"));
  • 17. } } final static Behavior<Hello> greetingBehavior = Behaviors.receive(Hello.class) .onMessage(Hello.class, (context, message) -> { context.getLog().info("Hello {}!", message.who); return Behavior.same(); }).build(); public static void main(String[] args) throws IOException { ActorSystem<Hello> actorSystem = ActorSystem.create(greetingBehavior, "my-system"); ActorRef<Hello> rootActor = actorSystem; rootActor.tell(new Hello("Johan")); rootActor.tell(new Hello("Devdays Vilnius audience")); System.out.println("Press that any-key to terminate"); System.in.read(); actorSystem.terminate(); } }
  • 18. } } final static Behavior<Hello> greetingBehavior = Behaviors.receive(Hello.class) .onMessage(Hello.class, (context, message) -> { context.getLog().info("Hello {}!", message.who); return Behavior.same(); }).build(); public static void main(String[] args) throws IOException { ActorSystem<Hello> actorSystem = ActorSystem.create(greetingBehavior, "my-system"); ActorRef<Hello> rootActor = actorSystem; rootActor.tell(new Hello("Johan")); rootActor.tell(new Hello("Devdays Vilnius audience")); System.out.println("Press that any-key to terminate"); System.in.read(); actorSystem.terminate(); } }
  • 19. import akka.actor.typed.{ActorRef, ActorSystem, Behavior} import akka.actor.typed.scaladsl.Behaviors import scala.io.StdIn object Sample1 { case class Hello(who: String) val greetingBehavior: Behavior[Hello] = Behaviors.receive { (ctx, hello) => ctx.log.info(s"Hello ${hello.who}!") Behaviors.same } def main(args: Array[String]): Unit = { val system = ActorSystem(greetingBehavior, "my-system") val rootActor: ActorRef[Hello] = system rootActor ! Hello("Johan") rootActor ! Hello("Devdays Vilnius audience") println("Press the any-key to terminate") StdIn.readLine() system.terminate() } }
  • 20. Let’s do another one right away The mystery of the changing state 🔎
  • 21. interface Command {} static class ChangeGreeting implements Command { public final String newGreeting; public ChangeGreeting(String newGreeting) { this.newGreeting = newGreeting; } } static class Hello implements Command { public final String who; public Hello(String who) { this.who = who; } } public static Behavior<Command> dynamicGreetingBehavior(String greeting) { return Behaviors.receive(Command.class) .onMessage(Hello.class, (context, message) -> { context.getLog().info(greeting + " " + message.who + "!"); return Behavior.same(); }).onMessage(ChangeGreeting.class, (context, changeGreeting) -> dynamicGreetingBehavior(changeGreeting.newGreeting) ).build(); } public static void main(String[] args) throws IOException { var actorSystem = ActorSystem.create(dynamicGreetingBehavior("Hello"), "my-system"); actorSystem.tell(new Hello("Johan")); actorSystem.tell(new ChangeGreeting("Sveiki")); actorSystem.tell(new Hello("Devdays Vilnius audience")); }
  • 22. interface Command {} static class ChangeGreeting implements Command { public final String newGreeting; public ChangeGreeting(String newGreeting) { this.newGreeting = newGreeting; } } static class Hello implements Command { public final String who; public Hello(String who) { this.who = who; } } public static Behavior<Command> dynamicGreetingBehavior(String greeting) { return Behaviors.receive(Command.class) .onMessage(Hello.class, (context, message) -> { context.getLog().info(greeting + " " + message.who + "!"); return Behavior.same(); }).onMessage(ChangeGreeting.class, (context, changeGreeting) -> dynamicGreetingBehavior(changeGreeting.newGreeting) ).build(); }
  • 23. static class Hello implements Command { public final String who; public Hello(String who) { this.who = who; } } public static Behavior<Command> dynamicGreetingBehavior(String greeting) { return Behaviors.receive(Command.class) .onMessage(Hello.class, (context, message) -> { context.getLog().info(greeting + " " + message.who + "!"); return Behavior.same(); }).onMessage(ChangeGreeting.class, (context, changeGreeting) -> dynamicGreetingBehavior(changeGreeting.newGreeting) ).build(); } public static void main(String[] args) throws IOException { var actorSystem = ActorSystem.create(dynamicGreetingBehavior("Hello"), "my-system"); actorSystem.tell(new Hello("Johan")); actorSystem.tell(new ChangeGreeting("Sveiki")); actorSystem.tell(new Hello("Devdays Vilnius audience")); }
  • 24. public static Behavior<Command> dynamicGreetingBehavior(String greeting) { return Behaviors.receive(Command.class) .onMessage(Hello.class, (context, message) -> { context.getLog().info(greeting + " " + message.who + "!"); return Behavior.same(); }).onMessage(ChangeGreeting.class, (context, changeGreeting) -> dynamicGreetingBehavior(changeGreeting.newGreeting) ).build(); } public static void main(String[] args) throws IOException { var actorSystem = ActorSystem.create(dynamicGreetingBehavior("Hello"), "my-system"); actorSystem.tell(new Hello("Johan")); actorSystem.tell(new ChangeGreeting("Sveiki")); actorSystem.tell(new Hello("Devdays Vilnius audience")); }
  • 25. sealed trait Command case class Hello(who: String) extends Command case class ChangeGreeting(newGreeting: String) extends Command def dynamicGreetingBehavior(greeting: String): Behavior[Command] = Behaviors.receive { (ctx, message) => message match { case Hello(who) => ctx.log.info(s"$greeting ${who}!") Behaviors.same case ChangeGreeting(newGreeting) => dynamicGreetingBehavior(newGreeting) } } def main(args: Array[String]): Unit = { val system = ActorSystem(dynamicGreetingBehavior("Hello"), "my-system") system ! Hello("Johan") system ! ChangeGreeting("Sveiki") system ! Hello("Devdays Vilnius audience") }
  • 26. But I don’t like it (the FP style, that is)
  • 27. static class MutableGreetingBehavior extends MutableBehavior<Command> { private final ActorContext<Command> context; private String greeting; public MutableGreetingBehavior(String initialGreeting, ActorContext<Command> context) { this.context = context; greeting = initialGreeting; } @Override public Behaviors.Receive<Command> createReceive() { return receiveBuilder() .onMessage(Hello.class, this::onHello) .onMessage(ChangeGreeting.class, this::onChangeGreeting) .build(); } private Behavior<Command> onHello(Hello hello) { context.getLog().info(greeting + " " + hello.who + "!"); return Behaviors.same(); } private Behavior<Command> onChangeGreeting(ChangeGreeting changeGreeting) { greeting = changeGreeting.newGreeting; return Behaviors.same(); } }
  • 28. static class MutableGreetingBehavior extends MutableBehavior<Command> { private final ActorContext<Command> context; private String greeting; public MutableGreetingBehavior(String initialGreeting, ActorContext<Co this.context = context; greeting = initialGreeting; } @Override public Behaviors.Receive<Command> createReceive() { return receiveBuilder() .onMessage(Hello.class, this::onHello) .onMessage(ChangeGreeting.class, this::onChangeGreeting) .build(); } private Behavior<Command> onHello(Hello hello) { context.getLog().info(greeting + " " + hello.who + "!"); return Behaviors.same(); }
  • 29. static class MutableGreetingBehavior extends MutableBehavior<Command> { private final ActorContext<Command> context; private String greeting; public MutableGreetingBehavior(String initialGreeting, ActorContext<Co this.context = context; greeting = initialGreeting; } @Override public Behaviors.Receive<Command> createReceive() { return receiveBuilder() .onMessage(Hello.class, this::onHello) .onMessage(ChangeGreeting.class, this::onChangeGreeting) .build(); } private Behavior<Command> onHello(Hello hello) { context.getLog().info(greeting + " " + hello.who + "!"); return Behaviors.same(); }
  • 30. static class MutableGreetingBehavior extends MutableBehavior<Command> { private final ActorContext<Command> context; private String greeting; public MutableGreetingBehavior(String initialGreeting, ActorContext<Co this.context = context; greeting = initialGreeting; } @Override public Behaviors.Receive<Command> createReceive() { return receiveBuilder() .onMessage(Hello.class, this::onHello) .onMessage(ChangeGreeting.class, this::onChangeGreeting) .build(); } private Behavior<Command> onHello(Hello hello) { context.getLog().info(greeting + " " + hello.who + "!"); return Behaviors.same(); }
  • 31. greeting = initialGreeting; } @Override public Behaviors.Receive<Command> createReceive() { return receiveBuilder() .onMessage(Hello.class, this::onHello) .onMessage(ChangeGreeting.class, this::onChangeGreeting) .build(); } private Behavior<Command> onHello(Hello hello) { context.getLog().info(greeting + " " + hello.who + "!"); return Behaviors.same(); } private Behavior<Command> onChangeGreeting(ChangeGreeting changeGreeti greeting = changeGreeting.newGreeting; return Behaviors.same(); } }
  • 32. public static void main(String[] args) { var system = ActorSystem.<Command>create( Behaviors.setup((context) -> new MutableGreetingBehavior("Hello", context)), "my-system" ); system.tell(new Hello("Johan")); system.tell(new ChangeGreeting("Sveiki")); system.tell(new Hello("Devdays Vilnius audience")); }
  • 33. • Discoverability, how are things related • More compile time type-safety, less runtime debugging Types helps productivity! (and results in more reliable systems in production) The need for strong/strict typing “Sending the wrong message to an actor is actually quite uncommon” – Myself, last week
  • 34. Burglar Alarm • enabled/disabled with a pin code • accepts notifications about “activity” • if enabled on activity, sound the alarm “Realistic” Example DIY
  • 35. interface AlarmMessage {} static class EnableAlarm implements AlarmMessage { public final String pinCode; public EnableAlarm(String pinCode) { this.pinCode = pinCode; } } static class DisableAlarm implements AlarmMessage { public final String pinCode; public DisableAlarm(String pinCode) { this.pinCode = pinCode; } } static class ActivityEvent implements AlarmMessage { }
  • 36. public static Behavior<AlarmMessage> enabledAlarm(String pinCode) { return Behaviors.receive(AlarmMessage.class) .onMessage( DisableAlarm.class, // predicate (disable) -> disable.pinCode.equals(pinCode), (context, message) -> { context.getLog().info("Correct pin entered, disabling alarm"); return disabledAlarm(pinCode); } ).onMessage(ActivityEvent.class, (context, activityEvent) -> { context.getLog().warning("EOEOEOEOEOE ALARM ALARM!!!"); return Behaviors.same(); }).build(); }
  • 37. public static Behavior<AlarmMessage> disabledAlarm(String pinCode) { return Behaviors.receive(AlarmMessage.class) .onMessage(EnableAlarm.class, // predicate (enable) -> enable.pinCode.equals(pinCode), (context, message) -> { context.getLog().info("Correct pin entered, enabling alarm"); return enabledAlarm(pinCode); } ).build(); }
  • 38. public static void main(String[] args) { var system = ActorSystem.create(enabledAlarm("0000"), "my-system"); system.tell(new ActivityEvent()); system.tell(new DisableAlarm("1234")); system.tell(new ActivityEvent()); system.tell(new DisableAlarm("0000")); system.tell(new ActivityEvent()); system.tell(new EnableAlarm("0000")); }
  • 39. sealed trait AlarmMessage case class EnableAlarm(pinCode: String) extends AlarmMessage case class DisableAlarm(pinCode: String) extends AlarmMessage case object ActivityEvent extends AlarmMessage def enabledAlarm(pinCode: String): Behavior[AlarmMessage] = Behaviors.receive { (context, message) => message match { case ActivityEvent => context.log.warning("EOEOEOEOEOE ALARM ALARM!!!") Behaviors.same case DisableAlarm(`pinCode`) => context.log.info("Correct pin entered, disabling alarm"); disabledAlarm(pinCode) case _ => Behaviors.unhandled } } def disabledAlarm(pinCode: String): Behavior[AlarmMessage] = Behaviors.receivePartial { case (context, EnableAlarm(`pinCode`)) => context.log.info("Correct pin entered, enabling alarm") enabledAlarm(pinCode) } def main(args: Array[String]): Unit = { val system = ActorSystem.create(enabledAlarm("0000"), "my-system") system.tell(ActivityEvent) system.tell(DisableAlarm("1234")) system.tell(ActivityEvent) system.tell(DisableAlarm("0000")) system.tell(ActivityEvent) system.tell(EnableAlarm("0000")) system.tell(ActivityEvent) }
  • 40. Request-response with other actors • In untyped actors the sender was auto-magically available • In Akka Typed the recipient of response has to be encoded in message (why?)
  • 41. Request-response with other actors Actor<ProtocolA> Actor<ProtocolB> RequestForB ActorRef<ResponseFromB> ResponseFromBProtocolA ?
  • 42. Request-response with other actors Actor<ProtocolA> Actor<ProtocolB> RequestForB ActorRef<ResponseFromB> ResponseFromBProtocolA ResponseFromB -> ProtocolA ?
  • 43. One off with Ask context.ask( ResponseFromB.class, actorB, Timeout.create(Duration.ofSeconds(5)), (ActorRef<ResponseFromB> respondTo) -> new RequestForB(respondTo), (ResponseFromB res, Throwable failure) -> { if (res != null) return new ProtocolAMessage(res); else throw new RuntimeException("Request failed", failure); } );
  • 44. Long live the adapter ActorRef<ResponseFromB> adapter = context.messageAdapter( ResponseFromB.class, (responseFromB) -> new ProtocolAMessage(responseFromB) ); actorB.tell(new RequestForB(adapter));
  • 45. Keeping parts of the protocol to ourselves ActorRef<ProtocolA> actorRef = … ActorRef<SubProtocolA> moreNarrowActorRef = actorRef.narrow(); ProtocolA SubProtocolA SubProtocolA2
  • 46. Distributed Systems –Leslie Lamport ”A distributed system is one in which the failure of a computer you didn't even know existed can render your own computer unusable”
  • 47. Why is it so hard? Reliability: power failure, old network 
 equipment, network congestion, coffee in router, 
 rodents, that guy in the IT dept., DDOS attacks… Latency: loopback vs local net vs shared congested local net vs internet Bandwidth: again loopback vs local vs shared local vs internet The Joys of Computer Networks:
  • 48. Partial Failure ✂ Node 1 Node 2 request response
  • 49. Partial Failure ✂ Node 1 Node 2 request 💥
  • 50. Partial Failure ✂ Node 1 Node 2 request 💥
  • 51. Partial Failure ✂ Node 1 Node 2 request response 💥
  • 52. Why do it, if it is so hard? Data or processing doesn’t fit a single machine
 Many objects, that should be kept in memory. Many not so powerful servers can be cheaper than a supercomputer. Elasticity
 Being able to scale in (less servers) and out (more servers) depending on load. Not paying for servers unless you need them. Resilience
 Building systems that will keep working in the face of failures or degrade gracefully.
  • 53. Actor Model vs Network Interaction already modelled as immutable messages
 Data travels over the network in packages, changes has to be explicitly sent back. At most once
 Data reaches a node on the other side at most once, but can be lost, already part of model! A recipient of a message can reply directly to sender
 Regardless if there were intermediate recipients of the message Messages not limited to request response
 Messages can flow in either direction when two systems are connected.
  • 56. Akka Cluster + Akka Typed ActorSystem ActorSystem ActorSystem
  • 61. Distributed Burglar Alarm • we can have any number of nodes • a sensor on any node can report activity to the alarm Example DYI Distributed
  • 62. static final ServiceKey<ActivityEvent> serviceKey = ServiceKey.create(ActivityEvent.class, "alarm"); interface AlarmMessage extends Serializable {} static class EnableAlarm implements AlarmMessage { public final String pinCode; public EnableAlarm(String pinCode) { this.pinCode = pinCode; } } static class DisableAlarm implements AlarmMessage { public final String pinCode; public DisableAlarm(String pinCode) { this.pinCode = pinCode; } } static class ActivityEvent implements AlarmMessage { }
  • 63. static final ServiceKey<ActivityEvent> serviceKey = ServiceKey.create(ActivityEvent.class, "alarm"); interface AlarmMessage extends Serializable {} static class EnableAlarm implements AlarmMessage { public final String pinCode; public EnableAlarm(String pinCode) { this.pinCode = pinCode; } } static class DisableAlarm implements AlarmMessage { public final String pinCode; public DisableAlarm(String pinCode) { this.pinCode = pinCode; } } static class ActivityEvent implements AlarmMessage { }
  • 64. public static Behavior<AlarmMessage> alarm(String pinCode) { return Behaviors.setup((context) -> { ActorRef<Receptionist.Command> receptionist = context.getSystem().receptionist(); receptionist.tell( Receptionist.register(serviceKey, context.getSelf().narrow())); return enabledAlarm(pinCode); }); }
  • 65. public static class SensorBehavior extends MutableBehavior<TriggerCommand> { private final ActorContext<TriggerCommand> context; private Set<ActorRef<ActivityEvent>> alarms = Collections.EMPTY_SET; public SensorBehavior(ActorContext<TriggerCommand> context) { this.context = context; // we need to transform the messages from the receptionist protocol // into our own protocol: ActorRef<Receptionist.Listing> adapter = context.messageAdapter( Receptionist.Listing.class, (listing) -> new AlarmActorUpdate(listing.getServiceInstances(serviceKey)) ); ActorRef<Receptionist.Command> receptionist = context.getSystem().receptionist(); receptionist.tell(Receptionist.subscribe(serviceKey, adapter)); } @Override public Behaviors.Receive<TriggerCommand> createReceive() { return receiveBuilder() .onMessage(TriggerSensor.class, this::onTrigger) .onMessage(AlarmActorUpdate.class, this::onAlarmActorUpdate) .build(); } private Behavior<TriggerCommand> onTrigger(TriggerSensor trigger) { final ActivityEvent activityEvent = new ActivityEvent(); if (alarms.isEmpty()) context.getLog().warning("Saw trigger but no alarms known yet"); alarms.forEach((alarm) -> alarm.tell(activityEvent) ); return Behaviors.same(); } private Behavior<TriggerCommand> onAlarmActorUpdate(AlarmActorUpdate update) { context.getLog().info("Got alarm actor list update"); alarms = update.alarms; return Behaviors.same(); } }
  • 66. public static class SensorBehavior extends MutableBehavior<TriggerCommand> { private final ActorContext<TriggerCommand> context; private Set<ActorRef<ActivityEvent>> alarms = Collections.EMPTY_SET; public SensorBehavior(ActorContext<TriggerCommand> context) { this.context = context; // we need to transform the messages from the receptionist protocol // into our own protocol: ActorRef<Receptionist.Listing> adapter = context.messageAdapter( Receptionist.Listing.class, (listing) -> new AlarmActorUpdate(listing.getServiceInstances(serviceKey)) ); ActorRef<Receptionist.Command> receptionist = context.getSystem().receptionist(); receptionist.tell(Receptionist.subscribe(serviceKey, adapter)); } @Override public Behaviors.Receive<TriggerCommand> createReceive() { return receiveBuilder() .onMessage(TriggerSensor.class, this::onTrigger) .onMessage(AlarmActorUpdate.class, this::onAlarmActorUpdate) .build(); } private Behavior<TriggerCommand> onTrigger(TriggerSensor trigger) { final ActivityEvent activityEvent = new ActivityEvent(); if (alarms.isEmpty()) context.getLog().warning("Saw trigger but no alarms known yet");
  • 67. ); ActorRef<Receptionist.Command> receptionist = context.getSystem().receptionist(); receptionist.tell(Receptionist.subscribe(serviceKey, adapter)); } @Override public Behaviors.Receive<TriggerCommand> createReceive() { return receiveBuilder() .onMessage(TriggerSensor.class, this::onTrigger) .onMessage(AlarmActorUpdate.class, this::onAlarmActorUpdate) .build(); } private Behavior<TriggerCommand> onTrigger(TriggerSensor trigger) { final ActivityEvent activityEvent = new ActivityEvent(); if (alarms.isEmpty()) context.getLog().warning("Saw trigger but no alarms known yet"); alarms.forEach((alarm) -> alarm.tell(activityEvent) ); return Behaviors.same(); } private Behavior<TriggerCommand> onAlarmActorUpdate(AlarmActorUpdate update) { context.getLog().info("Got alarm actor list update"); alarms = update.alarms; return Behaviors.same(); } }
  • 68. public static void main(String[] args) throws Exception { ActorSystem<AlarmMessage> system1 = ActorSystem.create(alarm("0000"), "my-cluster"); ActorSystem<TriggerCommand> system2 = ActorSystem.create(sensorBehavior(), "my-cluster"); ActorSystem<TriggerCommand> system3 = ActorSystem.create(sensorBehavior(), "my-cluster"); // first join the first node to itself to form a cluster Cluster node1 = Cluster.get(system1); node1.manager().tell(Join.create(node1.selfMember().address())); // then have node 2 and 3 join that cluster Cluster node2 = Cluster.get(system2); node2.manager().tell(Join.create(node1.selfMember().address())); Cluster node3 = Cluster.get(system3); node3.manager().tell(Join.create(node1.selfMember().address())); Scanner in = new Scanner(System.in); while (true) {
  • 69. // then have node 2 and 3 join that cluster Cluster node2 = Cluster.get(system2); node2.manager().tell(Join.create(node1.selfMember().address())); Cluster node3 = Cluster.get(system3); node3.manager().tell(Join.create(node1.selfMember().address())); Scanner in = new Scanner(System.in); while (true) { try { System.out.println("Enter 2 or 3 to trigger activity on that node"); int chosenNode = Integer.parseInt(in.next()); System.out.println("Triggering sensor on node " + chosenNode); if (chosenNode == 2) system2.tell(new TriggerSensor()); else if (chosenNode == 3) system3.tell(new TriggerSensor()); } catch (Exception ex) { // we don't care, loop! } } }
  • 70. Summary • On message - message another actor, change state or behavior • Types gives better guardrails and makes understanding the system easier • We can use the same abstraction for local and distributed
  • 71. GitHub repo with all samples in this talk bit.ly/2LnOU4L Akka typed docs doc.akka.io/docs/akka/2.5/typed/index.html More resources blog.akka.io - news and articles discuss.akka.io - forums developer.lightbend.com - samples github.com/akka/akka - sources and getting involved Further reading
  • 72. Questions? GitHub repo with all samples in this talk bit.ly/2LnOU4L