Akka
Patterns and anti-patterns
Roman Timushev
2014
About me
• Work at Qubell Inc.
• Scala since 2011
• Akka since 1.x
• Now: Scala, Akka, Play, MongoDB, RabbitMQ
Agenda
• Anti-patterns
• Ask is so cool
• Dependency injection for the win
• I like to block it, block it
• No mutable sta...
Ask is so cool
Tell, don’t ask:
classic code
class FineService {
def getFine(v: Double) = {
v * greedinessService.getGreediness()
}
}
cla...
Tell, don’t ask:
classic actor code
class FineService extends Actor {
def receive = {
case GetFine(v) =>
(greedinessServic...
Tell, don’t ask
• Works perfect until loaded
• Timeouts everywhere
• equal — you don’t get the exact cause
• different — u...
Tell, don’t ask:
invert control flow
class FineService extends Actor {
var greediness: Double = 0
def receive = {
case Get...
Dependency injection
for the win
Dependency injection:
actor references
trait AkkaComponent {
def actorSystem: ActorSystem
}
trait DividerComponent {
def d...
Dependency injection:
actor references
trait CalculatorComponentImpl extends CalculatorComponent {
this: AkkaComponent wit...
Dependency injection:
actor props
trait AkkaComponent {
def actorSystem: ActorSystem
}
trait DividerComponent {
def divide...
I like to
block it, block it
Blocking
class Blocker extends Actor {
import context._
def receive = {
case GetThreadCount =>
sender() ! Await.result(sle...
Blocking
• Run 1000 actors
• Send 1 request to every actor
• Default executor (fork-join, parallelism-max = 64)
Spin Await...
No mutable state
is so functional
Stateless actor
class StatelessActor extends Actor {
def receive = {
case Divide(a, b) => sender() ! (a / b)
}
}
class Cal...
Just future
class Calculator extends Actor {
def receive = {
case Calculate =>
Future { 84 / 2 } pipeTo self
case result: ...
Actor initialization
Actor initialization
• Actor parameters:
• Actor constructor
• Initializing message
• Initialize yourself
• Long initializ...
Actor initialization:
initializing message
class FineCalculator extends Actor {
var greediness = none[Double]
def receive ...
Actor initialization:
parameterized receive
class FineCalculator extends Actor {
def receive = uninitialized
def uninitial...
Scala.Rx
val a = Var(1)
val b = Var(2)
val c = Rx{ a() + b() }
val cObs = Obs(c) { println(c()) }
// prints 3
assert(c() =...
Actor initialization:
reactive receive
class FineCalculator extends Actor {
val greediness = Var(none[Double])
val actorRe...
Actor initialization:
initialize yourself
class FineCalculatorCallback extends Actor {
(context.actorSelection("..") ? Get...
Safe closures
Closing over actor state
When you use
• Future.apply
• future methods (map,
flatMap etc.)
• scheduler
And access
• this
• ...
Unsafe closures
class Computer extends Actor {
var counter = 0
override def receive: Receive = {
case Inc =>
val requester...
Local executor
trait LocalExecutor {
this: Actor =>
implicit val executor = new ExecutionContext {
override def execute(ru...
Safe closures
class Computer extends Actor with LocalExecutor {
var counter = 0
override def receive: Receive = super.rece...
Flow control
Flow control:
push
• The simplest option, use by default
Flow control:
throttle
• You should know maximum message rate in
advance
• TimerBasedThrottler (akka-contrib)
Flow control:
push with ack / pull
• Acknowledge individual messages or batches
• Difference: who is first
Questions?
References
Upcoming SlideShare
Loading in...5
×

Akka patterns

2,733

Published on

Published in: Software, Business, Technology
0 Comments
14 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,733
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
115
Comments
0
Likes
14
Embeds 0
No embeds

No notes for slide

Akka patterns

  1. 1. Akka Patterns and anti-patterns Roman Timushev 2014
  2. 2. About me • Work at Qubell Inc. • Scala since 2011 • Akka since 1.x • Now: Scala, Akka, Play, MongoDB, RabbitMQ
  3. 3. Agenda • Anti-patterns • Ask is so cool • Dependency injection for the win • I like to block it, block it • No mutable state is so functional • Patterns • Actor initialization • Safe closures • Flow control
  4. 4. Ask is so cool
  5. 5. Tell, don’t ask: classic code class FineService { def getFine(v: Double) = { v * greedinessService.getGreediness() } } class GreedinessService { def getGreediness(): Double = { db.query("select ...") } } class DbService { def query(s: String): Double = ??? }
  6. 6. Tell, don’t ask: classic actor code class FineService extends Actor { def receive = { case GetFine(v) => (greedinessService ? GetGreediness) .mapTo[Double].map(_ * v).pipeTo(sender()) } } class GreedinessService extends Actor { def receive = { case GetGreediness => (db ? Query("select ...")) .mapTo[Double].pipeTo(sender()) } } Timeout Timeout
  7. 7. Tell, don’t ask • Works perfect until loaded • Timeouts everywhere • equal — you don’t get the exact cause • different — unmanageable hell • Use thoughtful!
  8. 8. Tell, don’t ask: invert control flow class FineService extends Actor { var greediness: Double = 0 def receive = { case GetFine(v) => sender() ! greediness case SetGreediness(g) => greediness = g } } class GreedinessService extends Actor { def receive = { case ReloadGreediness => (db ? Query("select ...")) .mapTo[Double].map(SetGreediness).pipeTo(fineService) } }
  9. 9. Dependency injection for the win
  10. 10. Dependency injection: actor references trait AkkaComponent { def actorSystem: ActorSystem } trait DividerComponent { def divider: ActorRef } trait CalculatorComponent { def calculator: ActorRef }
  11. 11. Dependency injection: actor references trait CalculatorComponentImpl extends CalculatorComponent { this: AkkaComponent with DividerComponent => lazy val calculator = actorSystem.actorOf(Props(new Calculator)) class Calculator extends Actor { override val supervisorStrategy = ??? def receive = { case m: Divide => divider forward m } } }
  12. 12. Dependency injection: actor props trait AkkaComponent { def actorSystem: ActorSystem } trait DividerComponent { def divider: Props } trait CalculatorComponent { def calculator: ActorRef }
  13. 13. I like to block it, block it
  14. 14. Blocking class Blocker extends Actor { import context._ def receive = { case GetThreadCount => sender() ! Await.result(sleep(), 10 seconds) // or sender() ! spinAwait(sleep(), 10 seconds) } def sleep() = after(10 millis, system.scheduler)(Future.successful()) }
  15. 15. Blocking • Run 1000 actors • Send 1 request to every actor • Default executor (fork-join, parallelism-max = 64) Spin Await Threads 28 ~ 1000 Success rate 60% 100% Total time 410s 0.5s
  16. 16. No mutable state is so functional
  17. 17. Stateless actor class StatelessActor extends Actor { def receive = { case Divide(a, b) => sender() ! (a / b) } } class Calculator extends Actor { def receive = { case Calculate => context.actorOf(Props[StatelessActor]) ! Divide(84, 2) case result: Int => println(s"The answer is $result") } }
  18. 18. Just future class Calculator extends Actor { def receive = { case Calculate => Future { 84 / 2 } pipeTo self case result: Int => println(s"The answer is $result") } }
  19. 19. Actor initialization
  20. 20. Actor initialization • Actor parameters: • Actor constructor • Initializing message • Initialize yourself • Long initialization: • Blocking • Switching actor behavior with dropping • Switching actor behavior with stashing
  21. 21. Actor initialization: initializing message class FineCalculator extends Actor { var greediness = none[Double] def receive = { case SetGreediness(g) => greediness = some(g) case GetFine(v) => sender() ! (v * greediness.get) } }
  22. 22. Actor initialization: parameterized receive class FineCalculator extends Actor { def receive = uninitialized def uninitialized: Receive = { case SetGreediness(m) => context.become(initialized(m)) } def initialized(greediness: Double): Receive = { case GetFine(x) => sender() ! (x * greediness) } }
  23. 23. Scala.Rx val a = Var(1) val b = Var(2) val c = Rx{ a() + b() } val cObs = Obs(c) { println(c()) } // prints 3 assert(c() == 3) a() = 4 // prints 6 assert(c() == 6)
  24. 24. Actor initialization: reactive receive class FineCalculator extends Actor { val greediness = Var(none[Double]) val actorReceive = Rx { greediness().fold(uninitialized)(initialized) } val actorReceiveObs = Obs(actorReceive) { context.become(actorReceive()) } def receive = uninitialized def uninitialized: Receive = { case SetGreediness(g) => greediness() = some(g) } def initialized(g: Double): Receive = uninitialized orElse { case GetFine(v) => sender() ! (v * g) } }
  25. 25. Actor initialization: initialize yourself class FineCalculatorCallback extends Actor { (context.actorSelection("..") ? GetGreediness) .mapTo[Double].map(SetGreediness).pipeTo(self) def receive = uninitialized def uninitialized: Receive = { case SetGreediness(m) => context.become(initialized(m)) } def initialized(greediness: Double): Receive = { case GetFine(x) => sender() ! (x * greediness) } }
  26. 26. Safe closures
  27. 27. Closing over actor state When you use • Future.apply • future methods (map, flatMap etc.) • scheduler And access • this • vars • context • sender() you are asking for trouble
  28. 28. Unsafe closures class Computer extends Actor { var counter = 0 override def receive: Receive = { case Inc => val requester = sender() Future { counter += 1 // unsafe! requester ! counter } } }
  29. 29. Local executor trait LocalExecutor { this: Actor => implicit val executor = new ExecutionContext { override def execute(runnable: Runnable): Unit = self ! runnable override def reportFailure(t: Throwable): Unit = self ! t } def receive: Receive = { case r: Runnable => r.run() case t: Throwable => throw t } }
  30. 30. Safe closures class Computer extends Actor with LocalExecutor { var counter = 0 override def receive: Receive = super.receive orElse { case Inc => val requester = sender() Future { counter += 1 // safe requester ! counter } } }
  31. 31. Flow control
  32. 32. Flow control: push • The simplest option, use by default
  33. 33. Flow control: throttle • You should know maximum message rate in advance • TimerBasedThrottler (akka-contrib)
  34. 34. Flow control: push with ack / pull • Acknowledge individual messages or batches • Difference: who is first
  35. 35. Questions?
  36. 36. References
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×