Download Akka - Jfokus

Document related concepts
no text concepts found
Transcript
Akka Made Our Day
!
JFokus 2014
Daniel Deogun & Daniel Sawano
Email: [email protected], [email protected]
Twitter: @DanielDeogun, @DanielSawano
Who We Are
Daniel
Deogun
Daniel
Sawano
Omegapoint
Stockholm
-
Gothenburg
-
Malmoe
-
Umea
-
New
York
Agenda
- Akka
in
a
nutshell
- Akka
&
Java
- Domain
influences
- Lessons
learned
from
building
real
systems
with
Akka
Akka in a Nutshell
http://akka.io/
Akka in a Nutshell
Actors
Messages
Routers
Actor
System
Mailbox
[1]
[1] By Dickelbers (Own work) [CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons !
http://upload.wikimedia.org/wikipedia/commons/0/09/Sweden_postbox.JPG
Akka in a Nutshell
Actors
Messages
Routers
Actor
System
Mailbox
[1]
[1] By Dickelbers (Own work) [CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons !
http://upload.wikimedia.org/wikipedia/commons/0/09/Sweden_postbox.JPG
Akka in a Nutshell
Actors
Messages
Routers
Actor
System
Mailbox
[1]
[1] By Dickelbers (Own work) [CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons !
http://upload.wikimedia.org/wikipedia/commons/0/09/Sweden_postbox.JPG
Akka in a Nutshell
Actors
Messages
Routers
Actor
System
Mailbox
[1]
[1] By Dickelbers (Own work) [CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons !
http://upload.wikimedia.org/wikipedia/commons/0/09/Sweden_postbox.JPG
Akka in a Nutshell
Actors
Messages
Routers
Actor
System
Mailbox
[1]
[1] By Dickelbers (Own work) [CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons !
http://upload.wikimedia.org/wikipedia/commons/0/09/Sweden_postbox.JPG
Akka in a Nutshell
Actors
Messages
Routers
Actor
System
Mailbox
[1]
[1] By Dickelbers (Own work) [CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons !
http://upload.wikimedia.org/wikipedia/commons/0/09/Sweden_postbox.JPG
Our definition of
Legacy Code
Legacy \ˈle-gə-sē\
“: something that happened in the past or that comes from someone in
the past”
!
- Merriam-Webster
Our definition of
Legacy Code
Legacy \ˈle-gə-sē\
“: something that happened in the past or that comes from someone in
the past”
!
- Merriam-Webster
Legacy Code \ˈle-gə-sē\ \ˈkōd\
“: code that does not satisfy the characteristics of a reactive system”
- Deogun-Sawano
What is Legacy Code?
Characteristics
of
a
reactive
system,
as
defined
by
the
reactive
manifesto:
-
responsive
-
scalable
-
resilient
-
event-driven
reactivemanifesto.org
Java or Scala
[1]
[2]
I
want
to
build
an
application
with
Akka,
should
I
use
Java
or
Scala?
Well,
it
depends...
[1] https://duke.kenai.com/wave/.Midsize/Wave.png.png!
[2] http://www.scala-lang.org/
Java or Scala
Assume
we
want
to
build
a
machine
M
to
solve
a
problem
P
where,
• Efficiency
is
imperative
• Sequential
computations
shall
be
independent
• Implementation
of
M
shall
be
platform
independent
• Complexity
and
boilerplate
code
shall
be
reduced
• M’s
behavior
shall
be
verifiable
• Time
to
Market
is
essential
and
risks
minimized
Java or Scala
Pros & Cons
Assume
we
want
to
build
a
machine
M
to
solve
a
Scoreboard
problem
P
where,
Java:
Efficiency
is
imperative
Scala:
Sequential
computations
shall
be
independent
Implementation
of
M
shall
be
platform
independent
Complexity
and
boilerplate
code
shall
be
reduced
M’s
behavior
shall
be
verifiable
Time
to
Market
is
essential
and
risks
shall
be
minimized
Java or Scala
Pros & Cons
Assume
we
want
to
build
a
machine
M
to
solve
a
Scoreboard
problem
P
where,
Java:
I
Efficiency
is
imperative
Scala:
I
Sequential
computations
shall
be
independent
Implementation
of
M
shall
be
platform
independent
Complexity
and
boilerplate
code
shall
be
reduced
M’s
behavior
shall
be
verifiable
Time
to
Market
is
essential
and
risks
shall
be
minimized
X
Java or Scala
Pros & Cons
Assume
we
want
to
build
a
machine
M
to
solve
a
Scoreboard
problem
P
where,
Java:
II
Efficiency
is
imperative
Scala:
II
Sequential
computations
shall
be
independent
Implementation
of
M
shall
be
platform
independent
Complexity
and
boilerplate
code
shall
be
reduced
M’s
behavior
shall
be
verifiable
Time
to
Market
is
essential
and
risks
shall
be
minimized
X
X
Java or Scala
Pros & Cons
Assume
we
want
to
build
a
machine
M
to
solve
a
Scoreboard
problem
P
where,
Java:
III
Efficiency
is
imperative
Scala:
III
Sequential
computations
shall
be
independent
Implementation
of
M
shall
be
platform
independent
Complexity
and
boilerplate
code
shall
be
reduced
M’s
behavior
shall
be
verifiable
Time
to
Market
is
essential
and
risks
shall
be
minimized
X
X
X
Java or Scala
Pros & Cons
Assume
we
want
to
build
a
machine
M
to
solve
a
Scoreboard
problem
P
where,
Java:
III
Efficiency
is
imperative
Scala:
IIII
Sequential
computations
shall
be
independent
Implementation
of
M
shall
be
platform
independent
Complexity
and
boilerplate
code
shall
be
reduced
M’s
behavior
shall
be
verifiable
Time
to
Market
is
essential
and
risks
shall
be
minimized
X
X
X
X
Java or Scala
Pros & Cons
Assume
we
want
to
build
a
machine
M
to
solve
a
Scoreboard
problem
P
where,
Java:
IIII
Efficiency
is
imperative
Scala:
IIII
Sequential
computations
shall
be
independent
Implementation
of
M
shall
be
platform
independent
Complexity
and
boilerplate
code
shall
be
reduced
M’s
behavior
shall
be
verifiable
Time
to
Market
is
essential
and
risks
shall
be
minimized
X
X
X
X
X
Java or Scala
Pros & Cons
Assume
we
want
to
build
a
machine
M
to
solve
a
Scoreboard
problem
P
where,
Java:
IIII
Efficiency
is
imperative
Scala:
IIII
Sequential
computations
shall
be
independent
Implementation
of
M
shall
be
platform
independent
Complexity
and
boilerplate
code
shall
be
reduced
M’s
behavior
shall
be
verifiable
Time
to
Market
is
essential
and
risks
shall
be
minimized
X
X
X
X
X
X
Java or Scala
Conclusion
•Both
Java
and
Scala
works
well
with
Akka
!
•Choose
the
language
that
makes
most
sense
!
•Don’t
add
unnecessary
risk
Scoreboard
Java:
IIII
Scala:
IIII
Akka
All or nothing?
Decentralized
Parallelism
Supervision
Integration
Resilient
Abstraction
level
Akka
Modularization
Elastic
Distributed
Akka
All or nothing?
Parallelism
Decentralized
Supervision
Integration
Resilient
Abstraction
level
Akka
Modularization
Elastic
Distributed
Akka
All or nothing?
Parallelism
Supervision
Decentralized
Integration
Resilient
Abstraction
level
Akka
Modularization
Elastic
Distributed
Akka
All or nothing?
Parallelism
Supervision
Decentralized
Abstraction
level
Resilient
Akka
Modularization
Elastic
Distributed
Integration
Akka
All or nothing?
Parallelism
Supervision
Decentralized
Abstraction
level
Akka
Resilient
Integration
Elastic
Distributed
Modularization
Akka
All or nothing?
Parallelism
Supervision
Decentralized
Akka
Resilient
Integration
Elastic
Abstraction
level
Distributed
Modularization
Domain Specific
Requirements
• Akka
is
more
or
less
a
perfect
match
for
all
parallelizable
domains
!
• But
what
about
• reactive
domains
with
blocking
parts?
• legacy
domains
with
reactive
parts?
[1] By Renesis (Own work) [CC-BY-SA-2.5 (http://creativecommons.org/licenses/by-sa/2.5)], via Wikimedia Commons. http://upload.wikimedia.org/wikipedia/commons/1/19/Stop2.png
[1]
Blocking in a Reactive
Environment
• If
we
choose
Akka,
we
need
to
block
actors,
yuck!
!
!
oh
no
d
e
k
c
o
l
b
I’m
but
I’m
still
pretty
!
• The
main
advantage
is
that
we
can
reuse
actors
from
parallelizable
parts
but
are
there
any
downsides?
!
• The
other
option
is
to
use
legacy
design
Reactive in a Legacy
Environment?
Is
it
possible
to
replace
D
by
a
component
implemented
with
Akka?
Blocking
B
A
Blocking
Blocking
C
D
Blocking
Debugger
Friend or Foe?
We
often
get
the
question:
!
“The
asynchrony
in
Akka
makes
it
very
hard
to
use
the
debugger,
Am
I
doing
it
wrong?”
debugger in
Legacy Design
Legacy
Design
Object
A
Object
B
Object
N
debugger in
Legacy Design
Legacy
Design
Object
A
Object
B
debugger in
Legacy Design
Legacy
Design
Object
A
Object
B
Place
a
break
point
in
N
to
find
out
-
Which
value
caused
the
crash?
-
Who
created
it?
Object
N
debugger in
Reactive Design
Reactive
design
Break
point
in
actor
N
Supervision
We’re
reactive
Supervision
We’re
reactive
oh
no
d
e
k
c
o
l
b
m
I’
but
I’m
still
pretty
Supervision
Asynchronous
Supervision
Asynchronous
Failure
Supervision
Blocking
call
Synchronous
Supervision
Blocking
call
Synchronous
Supervision
Blocking
call
Send
failure
Synchronous
Supervision
Blocking
call
Send
failure
Synchronous
Supervision
!
!
!
private
private
private
private
ActorRef targetActor;!
ActorRef caller;!
AskParam askParam;!
Cancellable timeoutMessage;!
@Override!
public SupervisorStrategy supervisorStrategy() {!
return new OneForOneStrategy(0, Duration.Zero(), new Function<Throwable, SupervisorStrategy.Directive>() {!
public SupervisorStrategy.Directive apply(Throwable cause) {!
caller.tell(new Failure(cause), self());!
return SupervisorStrategy.stop();!
}!
});!
}!
@Override!
public void onReceive(final Object message) throws Exception {!
if (message instanceof AskParam) {!
askParam = (AskParam) message;!
caller = sender();!
targetActor = context().actorOf(askParam.props);!
context().watch(targetActor);!
targetActor.forward(askParam.message, context());!
final Scheduler scheduler = context().system().scheduler();!
timeoutMessage = scheduler.scheduleOnce(askParam.timeout.duration(), self(), new AskTimeout(), context().dispatcher(),
null);!
}!
else if (message instanceof Terminated) {!
sendFailureToCaller(new ActorKilledException("Target actor terminated."));!
timeoutMessage.cancel();!
context().stop(self());!
}!
else if (message instanceof AskTimeout) {!
sendFailureToCaller(new TimeoutException("Target actor timed out after " + askParam.timeout.toString()));!
context().stop(self());!
}!
else {!
unhandled(message);!
}!
}!
!
private void sendFailureToCaller(final Throwable t) {!
caller.tell(new Failure(t), self());!
}
Supervision
-Write
legacy
code
-Use
Akka
actors
Supervision
-Write
legacy
code
-Use
Akka
actors
Sequential
does
not
imply
synchronicity
The Shared Mutable
State Trap
!
Keeping
state
between
messages
in
an
actor
is
extremely
dangerous
because
it
may
cause
a
shared
mutable
state
!
!
The Shared Mutable
State Trap
Actor
Properties
-
One
message
queue
-
Only
one
message
is
processed
at
a
time
-
Messages
are
processed
in
order
received
-
An
actor
may
choose
to
divide
and
conquer
a
task
by
calling
other
actors
The Shared Mutable
State Trap
Actors
may
be
grouped
in
a
router
Router
Properties
-
Messages
are
distributed
among
actors
according
to
some
message
delivery
scheme,
eg
Round
Robin
or
Smallest
Mailbox
!
-
A
router
may
receive
a
lot
of
messages
The Shared Mutable
State Trap
Scenario
Actor
with
state
-
A
stateful
actor
is
part
of
a
router
!
-
It
uses
divide
and
conquer
to
solve
its
task
The Shared Mutable
State Trap
Scenario
Actor
with
state
-
Each
message
recived
from
the
router
resets
the
state
!
-
New
messages
are
inter
mixed
with
child
responses
!
-
Hence,
we
have
a
shared
mutable
state
The Shared Mutable
State Trap
Solution
-
Each
request
sent
by
the
router
results
in
a
“Gather”
actor
!
-
The
Gather
actor
is
responsible
for
collecting
the
result
!
result
Gather
actor
-
A
Gather
actor
is
NEVER
reused
Key Take-Aways
-
It’s
very
easy
to
accidentally
fall
back
to
sequential
“thinking”
with
state
!
-
Often
one
does
not
realize
this
until
the
system
is
placed
under
heavy
load
!
-
Try
to
avoid
state!
Readability
By
Various.
Edited
by:
W
H
Maw
and
J
Dredge
(Abandoned
library
clearance.
Self
photographed.)
[Public
domain],
via
Wikimedia
Commons
Implications of
untyped actors
!
Akka
actors
are
untyped
-
by
design
!
!
public void onReceive(Object message)
Implications of
untyped actors
!
Akka
actors
are
untyped
-
by
design
!
!
public void onReceive(Object message)
- Readability
- No
support
from
compiler/IDE
Message Handling V 1.0
!
!
@Override!
public void onReceive(Object message) {!
if (message instanceof SomeMessage) {!
doStuff();!
}!
else {!
unhandled(message);!
}!
}!
V 1.0 - If-else contd.
!
!
@Override!
public void onReceive(Object message) {!
if (message instanceof SomeMessage) {!
doStuff();!
}!
else if (message instanceof SomeOtherMessage) {!
doSomeOtherStuff();!
}!
else {!
unhandled(message);!
}!
}!
V 1.0 - If-else mess
!
!
@Override!
public void onReceive(Object message) {!
if (message instanceof SomeMessage) {!
doStuff();!
}!
else if (message instanceof SomeOtherMessage) {!
doSomeOtherStuff();!
}!
else if (message instanceof YetAnotherMessage) {!
doEvenMoreStuff();!
}!
else {!
unhandled(message);!
}!
}!
Evolution of message
handling
!
!
!
!
@Override!
public void onReceive(Object message) {!
...!
}!
!
http://upload.wikimedia.org/wikipedia/commons/thumb/6/69/Human_evolution.svg/2000px-Human_evolution.svg.png
V 2.0 - Overloading
!
public void onMessage(SomeMessage message) {...}!
!
public void onMessage(SomeOtherMessage message) {...}
V 2.0 - Overloading
!
public void onMessage(SomeMessage message) {...}!
!
public void onMessage(SomeOtherMessage message) {...}
!
@Override!
public void onReceive(Object message) {!
...!
!
!
}!
methods.get(message.getClass()).invoke(this, message);!
...!
V 2.1 - Annotations
!
!
class Worker extends BaseActor {!
!
@Response!
public void onMessage(SomeMessage message) {...}!
!
!
}
public void onMessage(SomeOtherMessage message) {...}!
V 3.0 - Contract
!
!
!
interface Messages {
!
!
!
}!
!
!
!
!
void doSomething(SomeMessage message);!
void doSomethingElse(SomeOtherMessage message);!
V 3.0 - Contract
!
!
!
interface Messages {
!
!
!
void doSomething(SomeMessage message);!
void doSomethingElse(SomeOtherMessage message);!
!
}!
!
!
!
!
SomeActor extends BaseActor implements Messages {...}!
V 3.0 - Contract
!
!
class Worker extends BaseActor implements Messages {!
!
!
!
!
!
}
public void handleResponse(SomeMessage message) {...}!
public void handleRequest(SomeOtherMessage message) {...}!
V 3.0 - Contract
!
!
BaseActor extends UntypedActor {!
!
!
}!
BaseActor() {!
methodDelegate = new MethodDelegate(this);!
}!
@Override !
public void onReceive(Object message) {!
if (methodDelegate.onReceive(message)) {!
return;!
}!
unhandled(message);!
}!
Before
!
class Worker extends BaseActor implements Messages {!
@Override!
public void onReceive(Object message) {!
if (message instanceof SomeMessage) {!
doStuff();!
}!
else if (message instanceof SomeOtherMessage) {!
doSomeOtherStuff();!
}!
else if (message instanceof YetAnotherMessage) {!
doEvenMoreStuff();!
}!
else {!
unhandled(message);!
}!
After
!
!
class Worker extends BaseActor implements Messages {
!
!
!
}!
!
public void handleResponse(SomeMessage message) {!
doStuff();!
}!
public void handleRequest(SomeOtherMessage message) {!
doSomeOtherStuff();!
}!
public void process(YetAnotherMessage message) {!
doEvenMoreStuff();!
}!
Conclusions
- Contracts
to
explicitly
define
behavior
works
pretty
-
well
Can
be
a
useful
tool
in
your
toolbox
Scala
can
give
similar
support
via
traits
&
match
Testing Akka Code
Interact
by
sending
messages
Integration
tests
BDD
Scenarios
Scenarios
Case
A1:
Sort
any
sequence
of
numbers
in
increasing
order
!
!
Given
a
sequence
of
numbers
in
decreasing
order
When
applying
the
sort
algorithm
Then
the
resulting
sequence
of
numbers
is
in
increasing
order
!
!
The Test
!
!
!
!
@Test!
!
public void caseA1() {!
!
!! ! given(sequence(9,8,7,6,5,4,3,2,1,0));!
!
!
!! ! whenSorting();!
!
!
!! ! thenResultIs(sequence(0,1,2,3,4,5,6,7,8,9));!
!
}!
Key Take-Aways
-
It’s
possible
to
use
Akka
in
legacy
code
Akka
is
Scala
&
Java
compliant
Akka
is
a
toolkit
with
a
lot
of
goodies
Stop
writing
legacy
code
Thank
you
@DanielDeogun
@DanielSawano