Fast Track to Akka

January 2, 2017 | Author: bsantoshraj | Category: N/A
Share Embed Donate


Short Description

Download Fast Track to Akka...

Description

Fast Track to Akka – Part 1 Philipp Haller Typesafe Inc.

July 11-12, 2012

1

Agenda

Why Akka?

Actors

Futures

Testing Actor Systems

2

Agenda

Why Akka?

Actors

Futures

Testing Actor Systems

3

The problem

It is way too hard to build I I I

correct highly-concurrent systems truly scalable systems fault-tolerant systems

... using today’s tools

4

Vision: Simpler Concurrency and Distribution

... with a single, unified I I I

5

Programming model Runtime Open-source distribution

Manage system overload

Scale up & out

7

Replicate and distribute for Fault-Tolerance

Architecture

9

Architecture

10

Architecture

11

Where is Akka used?

FINANCE I Stock trend Analysis & Simulation I Event-driven messaging systems BETTING & GAMING I Massive multiplayer online gaming I High throughput and transactional betting

12

TELECOM I Streaming media network gateways SIMULATION I 3D simulation engines E-COMMERCE I Social media community sites

Agenda

Why Akka?

Actors

Futures

Testing Actor Systems

13

What is an Actor?

14

What is an Actor?

15

What is an Actor?

16

What is an Actor?

17

Actor Model of Concurrency

18

I

Implements Message-Passing Concurrency

I

Share NOTHING

I

Isolated lightweight processes

I

Communicates through messages

I

Asynchronous and non-blocking

I

Each actor has a mailbox (message queue)

Actor Model Benefits

I

Easier to reason about

I

Raised abstraction level Easier to avoid

I

I I I I

I

19

Race conditions Deadlocks Starvation Live locks

Location Transparency, configuration-driven (adaptive) deployment

Basic Actor

1

case object Tick

2 3 4

class Counter extends Actor { var counter = 0 //STATE

5

def receive = { //BEHAVIOR case Tick => counter += 1 println(counter) }

6 7 8 9 10 11

20

}

Actor Systems

21

I

Every actor is created within the context of an actor system

I

The actor system is the unit for managing shared facilities like scheduling services, configuration, logging, etc.

I

Several actor systems with different configurations may co-exist within the same JVM instance (there is no global state within Akka itself)

I

There may be millions of actors within a single actor system

Creating Actors

I 1

I 1

I

22

Create an actor system: val system = ActorSystem()

Create an actor: val counter = system.actorOf(Props[Counter], "my-counter")

counter is an ActorRef

You can’t instantiate an Actor directly

I 1 2 3

4

5

6

7

23

This will throw an Exception: scala> new Counter akka.actor.ActorInitializationException: You cannot create an instance of [Counter] explicitly using the constructor (new). You have to use one of the factory methods to create a new actor. Either use: ’val actor = context.actorOf(Props[MyActor])’ (to create a supervised child actor from within an actor), or ’val actor = system.actorOf(Props[MyActor])’ (to create a top level actor from the ActorSystem), or ...

Send: !

I 1

I

24

Pronounced ”bang”, ”tell” or ”fire and forget” counter ! Tick

Asynchronous, does not block

Two-and-a-half ways to stop Actors I 1

Stop: system.stop(counter) will stop the actor after it has finished processing its current message

I 1

Send a Poison Pill: counter ! PoisonPill will stop the actor after it has finished processing all previously enqueued messages

I 1

Send a Kill message: counter ! Kill will make the actor fail, where the default supervisor action is to stop it

25

Exercise: A Simple Compute Actor

I I

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

I

26

A message with the length of a string when you receive a String A message with the square of an integer when you receive an Int

I

Create an object Main that extends App

I

Create an actor system

I

Create a ComputeActor

I

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

I

Shut down the actor system

Replying from an Actor

I 1 2 3 4 5 6 7

27

Reply using the sender ActorRef class ComputeActor extends Actor { def receive = { case s: String => sender ! s.length ... } }

The self

I 1

28

self is an ActorRef to be used from inside of the Actor case TickTwice => self ! Tick; self ! Tick

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:

I I I

1 2

import akka.pattern.{ ask, pipe } import akka.util.duration._

3 4 5 6 7 8

Using ”?” and an implicit timeout:

I 1 2

29

1

val msgContext = ... // some addition to reply val future = computeActor.ask("Hello")(2 seconds) future map { case reply: String => ComputeResult(msgContext, reply) } pipeTo sender

implicit val timeout: Timeout = 2 seconds val future = computeActor ? "Hello"

more on Futures later

Forwarding

1 2

class Router extends Actor { def nextActor: ActorRef = ...

3

def receive = { case message => nextActor forward message }

4 5 6 7 8

I

30

}

forward maintains original sender reference

Exercise: Add replies to ComputeActor

I

Reply to the sender with the computation result

I

Enable the duration DSL using the following import:

1

I

Add a test using ”ask” with an explicit timeout

I

Add a test using ”?” with an implicit timeout

I

Hint: await and obtain the result of a future using

1

I

31

import akka.util.duration._

Await.result(future, timeout)

Run using sbt or Eclipse

Agenda

Why Akka?

Actors

Futures

Testing Actor Systems

32

Future and Promise

33

I

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

I

A Promise is a write-handle to a single value (write-once) that should be made available

Blocking behaviour

Two blocking threads

What we really want

Using Futures with Actors 1 2 3

implicit val timeout: Timeout = 2 seconds // returns a future val future = computeActor ? GetAllResults

4 5 6 7 8

I

1 2 3 4 5

37

// do something asynchronously future map { case result: String => WrappedResult(result) } pipeTo nextStage

All operations creating futures need to know where callbacks are to be executed, described by an ExecutionContext import context.dispatcher // when inside an actor // OR implicit val ec = system.dispatcher // ActorSystem // OR implicit val ec = ExecutionContext.fromExecutor(...)

Future API: Monadic Operations

1 2 3 4

38

def def def def

map[S](f: T => S): Future[S] flatMap[S](f: T => Future[S]): Future[S] filter(p: T => Boolean): Future[T] foreach[U](f: T => U): Unit

Functional Composition

1 2 3 4 5 6 7 8 9

39

val rateQuote = Future { connection.getCurrentValue(USD) } val purchase = rateQuote map { quote => if (isProfitable(quote)) connection.buy(amount, quote) else throw new Exception("not profitable") }

Futures and For-Expressions

I

1

2

To enable for-expressions, futures also have flatMap, filter and foreach combinators val usdQuote = Future { connection.getCurrentValue(USD) } val chfQuote = Future { connection.getCurrentValue(CHF) }

3 4 5 6 7 8

40

val purchase = for { usd ...) Future.fold(futures)(0)((x, y) => ...)

Transformations: recover

1 2 3 4 5

I

44

val purchase: Future[Int] = rateQuote map { quote => connection.buy(amount, quote) } recover { case quoteExc: QuoteChangedException => 0 }

Converts exceptions into results

Transformations: sequence

1 2 3 4

I

45

val stringFutures = for (i Future { GET(url) } }

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

Future API

1

package akka.dispatch

2 3 4 5

47

trait Future[+T] extends Awaitable[T] { ... }

Awaitable[T] and Await 1

package akka.dispatch

2 3 4 5 6 7 8

object Await { // Blocks the current thread to wait for the given // Awaitable to be ready, returning // the Awaitable’s result def result[T](awaitable: Awaitable[T], atMost: Duration): T

9

// Blocks the current thread to wait for the given // Awaitable to be ready def ready[T println(s(i)) } def s(a: Any) = a.toString }

7 8 9

val actorRef = TestActorRef(new MyActor)(system) val actor: MyActor = actorRef.underlyingActor

10 11 12 13 14

54

// check business logic actor.s(1) must beEqualTo("1") // check behavior actor.receive.isDefinedAt("not defined") must beEqualTo(false)

TestKit with ScalaTest 1 2 3 4

import import import import

akka.testkit.{ TestKit, ImplicitSender } akka.actor.{ ActorSystem, Props } org.scalatest.WordSpec org.scalatest.junit.JUnitRunner

5 6 7 8

@org.junit.runner.RunWith(classOf[JUnitRunner]) class ActorsSpec extends TestKit(ActorSystem()) with ImplicitSender with WordSpec {

9

"A ComputeActor" should { "respond with the length of a string" in { val ref = system.actorOf(Props[ComputeActor]) ref ! "Hello world" expectMsg(11) } }

10 11 12 13 14 15 16 17

55

}

TestKit with Specs2 1 2 3 4

import import import import

akka.testkit.{ TestKit, ImplicitSender } akka.actor.{ ActorSystem, Props } org.specs2.mutable.Specification org.specs2.time.{ NoTimeConversions => NTC }

5 6 7

class ActorsSpec extends TestKit(ActorSystem()) with ImplicitSender with Specification with NTC {

8

"A ComputeActor" should { "respond with the length of a string" in { val ref = system.actorOf(Props[ComputeActor]) ref ! "Hello world" expectMsg(11) done // necessary because Specs2 wants a matcher } }

9 10 11 12 13 14 15 16 17

56

}

Exercise: TestActorRef and TestKit

I

Extract the computation logic of the ComputeActor class into two compute methods

I

Use a TestActorRef to test the compute methods

I

Using TestKit assertions check that a ComputeActor replies correctly to requests

I

TestKit assertions that might be useful (check out akka.io documentation for more):

1 2

57

expectMsg[T](obj: T): T expectMsgType[T: Manifest]

Test Probe

I 1 2 3 4 5 6 7 8 9 10 11 12

58

Insert test actors in order to verify message flow class ComputeActor extends Actor { def receive = { // ... case s: String => sender ! compute(s) } } val probe = TestProbe() ... // pass desired sender ActorRef explicitly computeActor.tell("Hello world", probe.ref) probe.expectMsg(11)

Exercise: Test Probe and More TestKit Assertions

59

I

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

I

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

I

Now change the implementation of the actor by adding/removing the use of futures (depending on whether you used them in step 1 or not).

Exercise: Accumulating Computation Results

60

I

Extend the previous exercise to include a second service to be queried in addition to the DB actor and use the auto-pilot feature of the TestProbes to automate the mocked response generation.

I

Include sleep statements simulating response latency, 1 second each, and verify that the combined result is received within 1.5 seconds.

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

Unless otherwise agreed, training materials may only be used for educational and reference purposes by individual named participants in a training course offered by Typesafe or a Typesafe training partner. Unauthorized reproduction, redistribution, or use of this material is prohibited.

61

View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF