Fast Track to Akka

Preview:

Citation preview

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 1/61

1

Fast Track to Akka – Part 1

Philipp Haller

Typesafe Inc.

July 11-12, 2012

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 2/61

2

Agenda

Why Akka?

Actors

Futures

Testing Actor Systems

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 3/61

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 4/614

The problem

It is way too hard to build correct highly-concurrent systems truly scalable systems fault-tolerant systems

... using today’s tools

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 5/615

Vision: Simpler Concurrency and Distribution

... with a single, unified Programming model Runtime Open-source distribution

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 6/61

Manage system overload

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 7/617

Scale up & out

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 8/61

Replicate and distribute

for Fault-Tolerance

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 9/619

Architecture

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 10/6110

Architecture

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 11/61

11

Architecture

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 12/61

12

Where is Akka used?

FINANCE

 Stock trend Analysis &Simulation

  Event-drivenmessaging systems

BETTING & GAMING

  Massive multiplayeronline gaming

 High throughput andtransactional betting

TELECOM

  Streaming medianetwork gateways

SIMULATION

  3D simulationengines

E-COMMERCE

 Social mediacommunity sites

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 13/61

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 14/61

14

What is an Actor?

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 15/61

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 16/61

16

What is an Actor?

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 17/61

A M d l f C

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 18/61

18

Actor Model of Concurrency

  Implements Message-Passing Concurrency

  Share NOTHING

  Isolated  lightweight processes  Communicates through messages

  Asynchronous and  non-blocking

 Each actor has a mailbox (message queue)

A M d l B fi

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 19/61

19

Actor Model Benefits

 Easier to reason about

 Raised abstraction level  Easier to avoid

Race conditions Deadlocks Starvation Live locks

  Location Transparency, configuration-driven (adaptive)

deployment

B i A t

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 20/61

20

Basic Actor

1   case object   Tick

2

3   class   Counter   extends   Actor {

4   var   counter = 0   //STATE

5

6   def   receive = {   //BEHAVIOR

7   case   Tick   =>

8   counter += 1

9   println(counter)

10

  }11   }

A t S t

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 21/61

21

Actor Systems

 Every actor is created within the context of an actor system

 The actor system is the unit for managing shared facilities like

scheduling services, configuration, logging, etc.  Several actor systems with different configurations may

co-exist within the same JVM instance (there is no globalstate within Akka itself)

 There may be millions of actors within a single actor system

Creating Actors

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 22/61

22

Creating Actors

 Create an actor system:

1   val   system = ActorSystem()

 Create an actor:

1   val   counter = system.actorOf(Props[Counter],

"my-counter")

  counter   is an  ActorRef

You can’t instantiate an Actor directly

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 23/61

23

You can t instantiate an Actor directly

 This will throw an  Exception:

1   scala>   new   Counter

2   akka.actor.ActorInitializationException:

3   You cannot create an instance of [Counter] explicitly

using the constructor (new).

4   You have to use one of the factory methods to create

a   new   actor. Either use:

5   ’val actor = context.actorOf(Props[MyActor])’   (to

create a supervised child actor from within an

actor), or

6   ’val actor = system.actorOf(Props[MyActor])’   (tocreate a top level actor from the ActorSystem), or

7   ...

Send: !

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 24/61

24

Send: !

 Pronounced ”bang”, ”tell” or ”fire and forget”

1   counter   !   Tick

 Asynchronous, does  not  block

Two and a half ways to stop Actors

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 25/61

25

Two-and-a-half ways to stop Actors

  Stop:

1   system.stop(counter)

will stop the actor after it has finished processing its current message

 Send a Poison Pill:

1   counter   !   PoisonPill

will stop the actor after it has finished processing all previously enqueued

messages

 Send a Kill message:1   counter   !   Kill

will make the actor fail, where the default supervisor action is to stop it

Exercise: A Simple Compute Actor

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 26/61

26

Exercise: A Simple Compute Actor

 Create a class ComputeActor that extends Actor   Implement the receive method which should print:

A message with the length of a string when you receive aString

A message with the square of an integer when you receive an

Int  Create an object Main that extends App

 Create an actor system

 Create a ComputeActor

 Send different types of messages (strings, ints, etc.) to theactor

 Shut down the actor system

Replying from an Actor

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 27/61

27

Replying from an Actor

 Reply using the sender ActorRef 

1   class   ComputeActor   extends   Actor {

2   def   receive = {

3   case   s: String   =>4   sender   !   s.length

5   ...

6   }

7   }

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 28/61

Send: ? and ask

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 29/61

29

Send: ? and ask

 Used to receive a reply without involving a mailbox  ”?” pronounced ”ask”  Returns directly with a  Future1, which allows transformation

and forwarding of the reply:

1   import   akka.pattern.{ ask, pipe }

2   import   akka.util.duration._

3

4   val   msgContext = ...   // some addition to reply

5   val   future = computeActor.ask("Hello")(2 seconds)

6   future map {   case   reply: String   =>

7   ComputeResult(msgContext, reply)

8   } pipeTo sender

 Using ”?” and an implicit timeout:

1   implicit val   timeout: Timeout = 2 seconds

2   val   future = computeActor   ?   "Hello"

1more on Futures later

Forwarding

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 30/61

30

Forwarding

1   class   Router   extends   Actor {

2   def   nextActor: ActorRef = ...

3

4

  def   receive = {5   case   message   =>

6   nextActor forward message

7   }

8   }

  forward  maintains original sender reference

Exercise: Add replies to ComputeActor

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 31/61

31

Exercise: Add replies to ComputeActor

 Reply to the sender with the computation result

 Enable the duration DSL using the following import:

1   import   akka.util.duration._

 Add a test using ”ask” with an explicit timeout

 Add a test using ”?” with an implicit timeout

 Hint: await and obtain the result of a future using

1   Await.result(future, timeout)

 Run using sbt or Eclipse

Agenda

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 32/61

32

g

Why Akka?

Actors

Futures

Testing Actor Systems

Future and Promise

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 33/61

33

  A Future is a read-handle to a single value (read-many) that

may become available   A Promise is a write-handle to a single value (write-once) that

should be made available

Blocking behaviour

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 34/61

g

Two blocking threads

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 35/61

g

What we really want

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 36/61

Using Futures with Actors

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 37/61

37

1   implicit val   timeout: Timeout = 2 seconds

2   // returns a future3   val   future = computeActor   ?   GetAllResults

4

5   // do something asynchronously

6   future map {   case   result: String   =>

7   WrappedResult(result)

8   } pipeTo nextStage

 All operations creating futures need to know where callbacksare to be executed, described by an   ExecutionContext

1   import   context.dispatcher   // when inside an actor2   // OR

3   implicit val   ec = system.dispatcher   // ActorSystem

4   // OR

5   implicit val   ec = ExecutionContext.fromExecutor(...)

Future API: Monadic Operations

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 38/61

38

1   def   map[S](f: T   =>   S): Future[S]

2

  def   flatMap[S](f: T   =>   Future[S]): Future[S]3   def   filter(p: T   =>   Boolean): Future[T]

4   def   foreach[U](f: T   =>   U): Unit

Functional Composition

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 39/61

39

1   val   rateQuote = Future {

2   connection.getCurrentValue(USD)

3   }

4

  val   purchase = rateQuote map {5   quote   =>

6   if   (isProfitable(quote))

7   connection.buy(amount, quote)

8   else throw new   Exception("not profitable")

9   }

Futures and For-Expressions

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 40/61

40

 To enable for-expressions, futures also have  flatMap,  filterand  foreach  combinators

1   val   usdQuote = Future {

connection.getCurrentValue(USD) }

2   val   chfQuote = Future {connection.getCurrentValue(CHF) }

3

4   val   purchase =   for   {

5   usd   <-   usdQuote

6   chf   <-   chfQuote

7   if   isProfitable(usd, chf)

8   }   yield   connection.buy(amount, chf)

Composing when using actors

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 41/61

41

  mapTo

1   val   f = (actor   ?   msg).mapTo[String]

  With for-expressions

1   val   r: Future[Int] =   for   {

2   a   <-   (webService   ?   GetResult).mapTo[Int]3   b   <-   (otherWebService   ?   GetResult).mapTo[Int]

4   }   yield   a * b

  . . . and in parallel

1   val   r: Future[Int] =   for   {

2   (a: Int, b: Int)   <-   (actorA   ?   Q) zip (actorB   ?   Q)

3   }   yield   a * b

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 42/61

Handling multiple Futures

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 43/61

43

1   val   futures = Seq(future1, future2, ...)

2

3   Future.firstCompletedOf(futures)4   Future.reduce(futures)((x, y)   =>   ...)

5   Future.fold(futures)(0)((x, y)   =>   ...)

Transformations: recover

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 44/61

44

1   val   purchase: Future[Int] = rateQuote map {

2   quote   =>   connection.buy(amount, quote)

3

  } recover {4   case   quoteExc: QuoteChangedException   =>   0

5   }

 Converts exceptions into results

Transformations: sequence

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 45/61

45

1   val   stringFutures =   for   (i   <-   1 to 10)

2   yield   Future { i.toString }

3   val   futureStrings: Future[Seq[String]] =4   Future.sequence(stringFutures)

  Turns a  collection  of Future[X] into a Future[collection[X]]

Transformations: traverse

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 46/61

46

1   val   futureListOfPages =

2   Future.traverse(getListOfUrls) { url   =>

3   Future { GET(url) }4   }

 Transforms a  collection[X] to Future[collection[Y]]

Future API

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 47/61

47

1   package   akka.dispatch

2

3   trait   Future[+T]   extends   Awaitable[T] {4   ...

5   }

Awaitable[T] and Await

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 48/61

48

1   package   akka.dispatch

2

3   object   Await {4   // Blocks the current thread to wait for the given

5   // Awaitable to be ready, returning

6   // the Awaitable’s result

7   def   result[T](awaitable: Awaitable[T],

8   atMost: Duration): T9

10   // Blocks the current thread to wait for the given

11   // Awaitable to be ready

12   def   ready[T <: Awaitable[_]](awaitable: T,

13

  atMost: Duration): T14   }

15

16   // Examples:

17   Await.result(future1, 3 seconds)

18   Await.ready(future2, 2 seconds)

Exercise: Back to the Future

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 49/61

49

 From a sequence of N integers produce a sequence of futureswhich are completed after the corresponding time inmilliseconds.

 Compute the list of completed results after 1 second, giventhat at least half of the futures were successful by then.

 By combining the futures one-by-one with

1   val   timeout = Future {

2   Thread.sleep(1000)

3   throw new   Exception("time’s up!")

4   }

construct a combined Future which will contain aSeq[Either[Exception, <result>]]

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 50/61

Exercise: More robust cancellation

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 51/61

51

 Extend the previous exercise so that the sequence of futurescontains services, mocked by a simple class with adef   dispose(): Unit  method, where the constructor sleeps

for a number of milliseconds.  Ensure that services which are not ready in time are disposed

of when their initialization finishes.

 Ensure that in case of overall failure all services are disposedof.

Agenda

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 52/61

52

Why Akka?

Actors

Futures

Testing Actor Systems

Testing in Akka

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 53/61

53

 Two ways to test:

Unit testing with  TestActorRef Integration testing with  TestKit  and  TestProbe

Unit Testing

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 54/61

54

  TestActorRef: an  ActorRef  which allows testing actors in a   single-threaded  environment behaves like a regular  ActorRef  otherwise

1   import   akka.testkit.TestActorRef

2

3   class   MyActor   extends   Actor {

4   def   receive = {   case   i: Int   =>   println(s(i)) }

5   def   s(a: Any) = a.toString6   }

7

8   val   actorRef = TestActorRef(new   MyActor)(system)

9   val   actor: MyActor = actorRef.underlyingActor

10

11   // check business logic

12   actor.s(1) must beEqualTo("1")

13   // check behavior

14   actor.receive.isDefinedAt("not defined") must

beEqualTo(false)

TestKit with ScalaTest

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 55/61

55

1   import   akka.testkit.{ TestKit, ImplicitSender }

2   import   akka.actor.{ ActorSystem, Props }

3   import   org.scalatest.WordSpec

4   import   org.scalatest.junit.JUnitRunner

5

6   @org.junit.runner.RunWith(classOf[JUnitRunner])

7   class   ActorsSpec   extends   TestKit(ActorSystem())   with

8   ImplicitSender   with   WordSpec {9

10   "A ComputeActor"   should {

11   "respond with the length of a string"   in {

12   val   ref = system.actorOf(Props[ComputeActor])

13   ref   !   "Hello world"14   expectMsg(11)

15   }

16   }

17   }

TestKit with Specs2

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 56/61

56

1   import   akka.testkit.{ TestKit, ImplicitSender }

2   import   akka.actor.{ ActorSystem, Props }

3   import   org.specs2.mutable.Specification

4   import   org.specs2.time.{ NoTimeConversions   =>   NTC }

5

6   class   ActorsSpec   extends   TestKit(ActorSystem())   with

7   ImplicitSender   with   Specification   with   NTC {

8

9   "A ComputeActor"   should {

10   "respond with the length of a string"   in {

11   val   ref = system.actorOf(Props[ComputeActor])

12   ref   !   "Hello world"

13   expectMsg(11)14   done   // necessary because Specs2 wants a matcher

15   }

16   }

17   }

Exercise: TestActorRef and TestKit

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 57/61

57

 Extract the computation logic of the ComputeActor class intotwo  compute  methods

 Use a TestActorRef to test the compute methods

 Using TestKit assertions check that a ComputeActor replies

correctly to requests  TestKit assertions that might be useful (check out akka.io

documentation for more):

1   expectMsg[T](obj: T): T

2   expectMsgType[T: Manifest]

Test Probe

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 58/61

58

 Insert test actors in order to verify message flow

1   class   ComputeActor   extends   Actor {

2   def   receive = {

3   // ...

4   case   s: String   =>

5   sender   !   compute(s)6   }

7   }

8   val   probe = TestProbe()

9   ...

10   // pass desired sender ActorRef explicitly

11   computeActor.tell("Hello world", probe.ref)

12   probe.expectMsg(11)

Exercise: Test Probe and More TestKit Assertions

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 59/61

59

 Write an actor which upon reception of a  Query  shall fire off a  DbRequest  to an actor which has been passed to it in aconstructor argument; the reply shall go back to the originalsender, wrapped in a  Response(rsp: Any).

 Implement a test case which verifies this process, mocking theDB actor using a  TestProbe.

 Now change the implementation of the actor byadding/removing the use of futures (depending on whether

you used them in step 1 or not).

Exercise: Accumulating Computation Results

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 60/61

60

 Extend the previous exercise to include a second service to bequeried in addition to the DB actor and use the auto-pilotfeature of the  TestProbes  to automate the mocked response

generation.   Include sleep statements simulating response latency, 1 second

each, and verify that the combined result is received within1.5 seconds.

Copyright (c) 2011, 2012 Typesafe, Inc. All rights reserved.

8/9/2019 Fast Track to Akka

http://slidepdf.com/reader/full/fast-track-to-akka 61/61

61

Unless otherwise agreed, training materials may only be used foreducational and reference purposes by individual named

participants in a training course offered by Typesafe or a Typesafetraining partner. Unauthorized reproduction, redistribution, or useof this material is prohibited.