91
Konrad 'ktoso' Malawski GeeCON 2014 @ Kraków, PL Konrad `@ktosopl` Malawski Fresh from the Oven - akka

Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Embed Size (px)

Citation preview

Page 1: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Konrad 'ktoso' MalawskiGeeCON 2014 @ Kraków, PL

Konrad `@ktosopl` Malawski

Fresh from the Oven - akka

Page 2: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Konrad 'ktoso' MalawskiGeeCON 2014 @ Kraków, PL

Konrad `@ktosopl` Malawski

Fresh from the Oven - akka gets Typed

Page 3: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Konrad `ktoso` Malawski

Akka Team, Reactive Streams TCK

Page 4: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Konrad `@ktosopl` Malawski

akka.iotypesafe.comgeecon.org

Java.pl / KrakowScala.plsckrk.com / meetup.com/Paper-Cup @ London

GDGKrakow.pl lambdakrk.pl

Page 5: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Nice to meet you! Who are you guys?

Page 6: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Disclaimer

Modules discussed in this talk arepre-experimental or not even released yet.

Also known as“don’t use in production”,“please give us feedback”,

“docs are work in progress”etc.

Everything shown is experimental! The cake is a lie!

Page 7: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Agenda

• What Akka is at it’s heart

• Old Typed Actors + some background

• Akka Typed

• Akka Streams / Reactive Streams

• Wrapping up

experimentalexperimental

not released yet

Page 8: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Actors

Page 9: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Actors“untyped”

Page 10: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

The Actor Model

The Actor Model as defined by Hewitt, Bishop and Steiger in 1973 is a computational model that expresses exactly what it means for computation to be distributed.

Actors can only communicate by exchanging messages. Upon reception of a message an Actor can do the following three fundamental actions:

• send a finite number of messages to Actors it knows • create a finite number of new Actors • designate the behavior to be applied to the next message

Page 11: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Why Untyped?Inspired by Erlang, that’s untyped as well.

Modelling “become” is non obvious: “what about races in sending msgs which change state?”

Networking is untyped - sorry.

Pattern matching makes extracting types simple.

Several failed attempts (incl. in Erlang)

(Yes, we know session types).

Page 12: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed

Page 13: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed

NOT the Old Typed Actors module

Page 14: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka TypedNOT the Old Typed Actors module

Page 15: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Old Typed ActorsWere never intended to be a core abstraction.

Just a “bridge from Java-land to Actor-land”.

A note on Distributed Computing by Jim Waldo et al.

Page 16: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Old Typed ActorsWere never intended to be a core abstraction.

Just a “bridge from Java-land to Actor-land”.

trait Squarer { def squareDontCare(i: Int): Unit //fire-forget def square(i: Int): Future[Int] //non-blocking send-request-reply def squareNowPlease(i: Int): Option[Int] //blocking send-request-reply def squareNow(i: Int): Int //blocking send-request-reply @throws(classOf[Exception]) //declare it or you will get an UndeclaredThrowableException def squareTry(i: Int): Int //blocking send-request-reply with possible exception}

A note on Distributed Computing by Jim Waldo et al.

Page 17: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Old Typed ActorsWere never intended to be a core abstraction.

Just a “bridge from Java-land to Actor-land”.

trait Squarer { def squareDontCare(i: Int): Unit //fire-forget def square(i: Int): Future[Int] //non-blocking send-request-reply def squareNowPlease(i: Int): Option[Int] //blocking send-request-reply def squareNow(i: Int): Int //blocking send-request-reply @throws(classOf[Exception]) //declare it or you will get an UndeclaredThrowableException def squareTry(i: Int): Int //blocking send-request-reply with possible exception}

NOT what you’re looking for

A note on Distributed Computing by Jim Waldo et al.

Page 18: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

The old “Typed Actors”trait Squarer { def squareDontCare(i: Int): Unit //fire-forget def square(i: Int): Future[Int] //non-blocking send-request-reply def squareNowPlease(i: Int): Option[Int] //blocking send-request-reply def squareNow(i: Int): Int //blocking send-request-reply @throws(classOf[Exception]) //declare it or you will get an UndeclaredThrowableException def squareTry(i: Int): Int //blocking send-request-reply with possible exception}

NOT what you’re looking for

- 10x slower than plain Actors (because reflection)- way too easy to expose blocking APIs (oh no!)- interface cannot express become- too much magic

http://stackoverflow.com/questions/28516273/akka-typed-actors-in-java

Page 19: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed

Akka Typed is primarily the work of Dr Roland Kuhn

Page 20: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: What’s different?

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

class Greeter extends Actor {

def receive = { case msg: Greet ⇒ println(s"Hello ${msg.whom}!") sender() ! Greeted(msg.whom) }

}

val system: ActorSystem = ActorSystem(“akka-actor-system“)val greeter = system.actorOf(Props[Greeter])

system ! Greet("kapi", system.deadLetters)

Akka Actor

Page 21: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: What’s different?

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

val greeter = Total[Greet] { msg ⇒ println(s"Hello ${msg.whom}!") msg.replyTo ! Greeted(msg.whom) Same}

val system: ActorSystem[Greet] = ActorSystem(“typed", Props(totalGreeter))

system ! Greet("kapi", system.deadLetters)

class Greeter extends Actor {

def receive = { case msg: Greet ⇒ println(s"Hello ${msg.whom}!") sender() ! Greeted(msg.whom) }

}

val system: ActorSystem = ActorSystem(“akka-actor-system“)val greeter = system.actorOf(Props[Greeter])

system ! Greet("kapi", system.deadLetters)

Akka Actor Akka Typed

Page 22: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: What’s different?

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

val greeter = Total[Greet] { msg ⇒ println(s"Hello ${msg.whom}!") msg.replyTo ! Greeted(msg.whom) Same}

val system: ActorSystem[Greet] = ActorSystem(“typed", Props(totalGreeter))

system ! Greet("kapi", system.deadLetters)

class Greeter extends Actor {

def receive = { case msg: Greet ⇒ println(s"Hello ${msg.whom}!") sender() ! Greeted(msg.whom) }

}

val system: ActorSystem = ActorSystem(“akka-actor-system“)val greeter = system.actorOf(Props[Greeter])

system ! Greet("kapi", system.deadLetters)

Akka Actor Akka Typed

The main concept is Behaviour[T] Explicit protocols for the win!

Page 23: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: What’s different?

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

val greeter = Total[Greet] { msg ⇒ println(s"Hello ${msg.whom}!") msg.replyTo ! Greeted(msg.whom) Same}

val system: ActorSystem[Greet] = ActorSystem(“typed", Props(totalGreeter))

system ! Greet("kapi", system.deadLetters)

class Greeter extends Actor {

def receive = { case msg: Greet ⇒ println(s"Hello ${msg.whom}!") sender() ! Greeted(msg.whom) }

}

val system: ActorSystem = ActorSystem(“akka-actor-system“)val greeter = system.actorOf(Props[Greeter])

system ! Greet("kapi", system.deadLetters)

Akka Actor Akka Typed

Since Behaviour[Greet] is typed, msg is-a Greet.

Page 24: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: What’s different?

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

val greeter = Total[Greet] { msg ⇒ println(s"Hello ${msg.whom}!") msg.replyTo ! Greeted(msg.whom) Same}

val system: ActorSystem[Greet] = ActorSystem(“typed", Props(totalGreeter))

system ! Greet("kapi", system.deadLetters)

class Greeter extends Actor {

def receive = { case msg: Greet ⇒ println(s"Hello ${msg.whom}!") sender() ! Greeted(msg.whom) }

}

val system: ActorSystem = ActorSystem(“akka-actor-system“)val greeter = system.actorOf(Props[Greeter])

system ! Greet("kapi", system.deadLetters)

Akka Actor Akka Typed

The Behaviour[T]is the receive.

Page 25: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: What’s different?

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

val greeter = Total[Greet] { msg ⇒ println(s"Hello ${msg.whom}!") msg.replyTo ! Greeted(msg.whom) Same}

val system: ActorSystem[Greet] = ActorSystem(“typed", Props(totalGreeter))

system ! Greet("kapi", system.deadLetters)

class Greeter extends Actor {

def receive = { case msg: Greet ⇒ println(s"Hello ${msg.whom}!") sender() ! Greeted(msg.whom) }

}

val system: ActorSystem = ActorSystem(“akka-actor-system“)val greeter = system.actorOf(Props[Greeter])

system ! Greet("kapi", system.deadLetters)

Akka Actor Akka Typed

sender() is no more.Explicit protocols for the win!

Page 26: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: What’s different?

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

val greeter = Total[Greet] { msg ⇒ println(s"Hello ${msg.whom}!") msg.replyTo ! Greeted(msg.whom) Same}

val system: ActorSystem[Greet] = ActorSystem(“typed", Props(totalGreeter))

system ! Greet("kapi", system.deadLetters)

class Greeter extends Actor {

def receive = { case msg: Greet ⇒ println(s"Hello ${msg.whom}!") sender() ! Greeted(msg.whom) }

}

val system: ActorSystem = ActorSystem(“akka-actor-system“)val greeter = system.actorOf(Props[Greeter])

system ! Greet("kapi", system.deadLetters)

Akka Actor Akka Typed

sender() is no more.Explicit protocols for the win!

final case class Greet(whom: String, replyTo: ActorRef[Greeted])

Page 27: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: What’s different?

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

val greeter = Total[Greet] { msg ⇒ println(s"Hello ${msg.whom}!") msg.replyTo ! Greeted(msg.whom) Same}

val system: ActorSystem[Greet] = ActorSystem(“typed", Props(totalGreeter))

system ! Greet("kapi", system.deadLetters)

class Greeter extends Actor {

def receive = { case msg: Greet ⇒ println(s"Hello ${msg.whom}!") sender() ! Greeted(msg.whom) }

}

val system: ActorSystem = ActorSystem(“akka-actor-system“)val greeter = system.actorOf(Props[Greeter])

system ! Greet("kapi", system.deadLetters)

Akka Actor Akka Typed

ActorRef[T] is now typed!

Page 28: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: What’s different?

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

val greeter = Total[Greet] { msg ⇒ println(s"Hello ${msg.whom}!") msg.replyTo ! Greeted(msg.whom) Same}

val system: ActorSystem[Greet] = ActorSystem(“typed", Props(totalGreeter))

system ! Greet("kapi", system.deadLetters)

class Greeter extends Actor {

def receive = { case msg: Greet ⇒ println(s"Hello ${msg.whom}!") sender() ! Greeted(msg.whom)

}

}

val system: ActorSystem = ActorSystem(“akka-actor-system“)val greeter = system.actorOf(Props[Greeter])

system ! Greet("kapi", system.deadLetters)

Akka Actor Akka Typed

become()is required.And replaced by returning the “next” Behaviour[T]

// context.become(receive)

Page 29: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: What’s different?

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

val greeter = Total[Greet] { msg ⇒ println(s"Hello ${msg.whom}!") msg.replyTo ! Greeted(msg.whom) Same}

val system: ActorSystem[Greet] = ActorSystem(“typed", Props(totalGreeter))

system ! Greet("kapi", system.deadLetters)

class Greeter extends Actor {

def receive = { case msg: Greet ⇒ println(s"Hello ${msg.whom}!") sender() ! Greeted(msg.whom)

}

}

val system: ActorSystem = ActorSystem(“akka-actor-system“)val greeter = system.actorOf(Props[Greeter])

system ! Greet("kapi", system.deadLetters)

Akka Actor Akka Typed

become()is required.And replaced by returning the “next” Behaviour[T]

On a conceptual level at least,we provide Static[T]if you don’t need become.

// context.become(receive)

Page 30: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: What’s different?

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

val greeter = Total[Greet] { msg ⇒ println(s"Hello ${msg.whom}!") msg.replyTo ! Greeted(msg.whom) Same}

val system: ActorSystem[Greet] = ActorSystem(“typed", Props(totalGreeter))

system ! Greet("kapi", system.deadLetters)

class Greeter extends Actor {

def receive = { case msg: Greet ⇒ println(s"Hello ${msg.whom}!") sender() ! Greeted(msg.whom)

}

}

val system: ActorSystem = ActorSystem(“akka-actor-system“)val greeter = system.actorOf(Props[Greeter])

system ! Greet("kapi", system.deadLetters)

Akka Actor Akka Typed

become()is required.And replaced by returning the “next” Behaviour[T]

Special behaviors:Same / Unhandled / Empty / Stopped / Ignore

// context.become(receive)

Page 31: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: What’s different?

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

val greeter = Total[Greet] { msg ⇒ println(s"Hello ${msg.whom}!") msg.replyTo ! Greeted(msg.whom) Same}

val system: ActorSystem[Greet] = ActorSystem(“typed", Props(totalGreeter))

system ! Greet("kapi", system.deadLetters)

class Greeter extends Actor {

def receive = { case msg: Greet ⇒ println(s"Hello ${msg.whom}!") sender() ! Greeted(msg.whom) }

}

val system: ActorSystem = ActorSystem(“akka-actor-system“)val greeter = system.actorOf(Props[Greeter])

system ! Greet("kapi", system.deadLetters)

Akka Actor Akka Typed

“Root actor” is not user-defined for ActorSystem[T]

Encourages thinking about supervision.

Page 32: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: Behaviors

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

Static[T] - if become not neededTotal[T] - behavior is total functionPartial[T] - behavior is partial function

Full[T] - when interested in system signalsFullTotal[T] or ActorContext

Page 33: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: Behaviors

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

object HelloWorld { final case class Greet(whom: String, replyTo: ActorRef[Greeted]) final case class Greeted(whom: String) val greeter = Static[Greet] { msg ⇒ println(s"Hello ${msg.whom}!") msg.replyTo ! Greeted(msg.whom) }}

Static[T] - if become not neededTotal[T] - behavior is total functionPartial[T] - behavior is partial function

Full[T] - when interested in system signalsFullTotal[T] or ActorContext

Page 34: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: Behaviors

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

Static[T] - if become not neededTotal[T] - behavior is total functionPartial[T] - behavior is partial function

Full[T] - when interested in system signalsFullTotal[T] or ActorContext

val master = Full[WorkProtocol] { case Msg(ctx, w: Work) ⇒ ctx.spawn(Props(worker), s"worker-${w.id}") ! w // ...}

Page 35: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: Behavior Combinators

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

Combine behaviors:final case class And[T](left: Behavior[T], right: Behavior[T]) extends Behavior[T] { /* … */ }

final case class Or[T](left: Behavior[T], right: Behavior[T]) extends Behavior[T] { /* … */ }

Smarter “left orElse right”

Page 36: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed: narrow / widen

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

def narrow[U <: T]: Behavior[U]

def widen[U >: T](matcher: PartialFunction[U, T]): Behavior[U]

Narrowing a Behavior is always safe

Widening requires help in form of a matcher:

Page 37: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed

http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html

More types! Root Actor is user-defined

sender() is gone

Lifecycle hooks are now system messages

Awesome possibilities to combine Behaviours

Early work-in-progress preview in 2.4.x (Currently emulated on top of Akka-Actor)

Page 38: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Typed

Page 39: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Reactive Streams

Page 40: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Reactive StreamsAkka Streams

Page 41: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Reactive Streams

http://www.reactive-streams.org/

Page 42: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Reactive Streams

Page 43: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Reactive Streams - Who?

http://reactive-streams.org

Kaazing Corp.RxJava @ Netflix,

Reactor @ Pivotal (SpringSource),Vert.x @ Red Hat,

Twitter,Akka Streams, Slick @ Typesafe,

Spray @ Spray.io,Oracle,

OpenJDK (?) – Doug Lea - SUNY Oswego …

Page 44: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

What is back-pressure?

Page 45: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure?

Page 46: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? WAT!

Page 47: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? WAT!

What if the buffer overflows?

Page 48: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? Push + Drop + Resend (a)

Use bounded buffer, drop messages + require re-sending

Page 49: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? Push + Drop + Resend (a)

Kernel does this!Routers do this!

(TCP)

Use bounded buffer, drop messages + require re-sending

Page 50: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? Unbounded queues != solution (b)

Increase buffer size… Well, while you have memory available!

Page 51: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? Unbounded queues != solution (b)

Page 52: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure?Reactive-Streams

= “Dynamic Push/Pull”

Page 53: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Just push – not safe when Slow Subscriber

Just pull – too slow when Fast Subscriber

Back-pressure? RS: Dynamic Push/Pull

Page 54: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Solution:Dynamic adjustment

Back-pressure? RS: Dynamic Push/Pull

Just push – not safe when Slow Subscriber

Just pull – too slow when Fast Subscriber

Page 55: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? RS: Dynamic Push/PullSlow Subscriber sees it’s buffer can take 3 elements. Publisher will never blow up it’s buffer.

Page 56: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? RS: Dynamic Push/PullFast Publisher will send at-most 3 elements. This is pull-based-backpressure.

Page 57: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? RS: Dynamic Push/Pull

Fast Subscriber can issue more Request(n), before more data arrives!

Page 58: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? RS: Dynamic Push/PullFast Subscriber can issue more Request(n), before more data arrives.

Publisher can accumulate demand.

Page 59: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? RS: Accumulate demandPublisher accumulates total demand per subscriber.

Page 60: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? RS: Accumulate demandTotal demand of elements is safe to publish. Subscriber’s buffer will not overflow.

Page 61: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? RS: Requesting “a lot”Fast Subscriber can issue arbitrary large requests, including “gimme all you got” (Long.MaxValue)

Page 62: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? RS: Dynamic Push/Pull

MAX

speed

Page 63: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressure? RS: Dynamic Push/Pull

Easy

MAX

speed

Page 64: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Back-pressureFile upload demo with Akka HTTP

Page 65: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams – Linear Flow

Page 66: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams – Linear Flow

Page 67: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams – Linear Flow

Page 68: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams – Linear Flow

Page 69: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams – Linear Flow

Flow[Double].map(_.toInt). [...]

No Source attached yet.“Pipe ready to work with Doubles”.

Page 70: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams – Linear Flow

implicit val sys = ActorSystem("scalar-sys")implicit val mat = ActorFlowMaterializer()

Source(1 to 3).runWith(Sink.foreach(println))

Page 71: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams – Linear Flow

implicit val sys = ActorSystem("scalar-sys")implicit val mat = ActorFlowMaterializer()

Source(1 to 3).runWith(Sink.foreach(println))

// sugar for runWithSource(1 to 3).foreach(println)

Page 72: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams – Linear Flow

implicit val sys = ActorSystem("scalar-sys")implicit val mat = ActorFlowMaterializer()

Source(1 to 3).runWith(Sink.foreach(println))

// sugar for runWithSource(1 to 3).foreach(println)

Sink.foldSink.headSink.ignoreSink.publisherSink.cancelled// your own Sink…

Page 73: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams <-> Actors – Advancedval subscriber = ActorSubscriber( system.actorOf(Props[SubStreamParent], ”parent”))

Source(1 to 100) .map(_.toString) .filter(_.length == 2) .drop(2) .conflate(seed => seed)((acc, i) => acc + i) .groupBy(_.last) .runWith(subscriber)

All the usual ops available for Linear Flows.

Page 74: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams <-> Actors – Advancedval subscriber = ActorSubscriber( system.actorOf(Props[SubStreamParent], ”parent”))

Source(1 to 100) .map(_.toString) .filter(_.length == 2) .drop(2) .conflate(seed => seed)((acc, i) => acc + i) .groupBy(_.last) .runWith(subscriber)

Aggregating values until downstream demand comes.

Page 75: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams <-> Actors – Advancedval subscriber = ActorSubscriber( system.actorOf(Props[SubStreamParent], ”parent”))

Source(1 to 100) .map(_.toString) .filter(_.length == 2) .drop(2) .conflate(seed => seed)((acc, i) => acc + i) .groupBy(_.last) .runWith(subscriber)

Creates a stream of streams:Source[Source[String]]

Page 76: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams: Graphs

val p: Publisher[String] = FlowGraph.closed(out) { implicit b ⇒ o ⇒ val merge = b.add(new StrictRoundRobin[String])

in1 ~> merge.in(0) in2 ~> merge.in(1) merge.out ~> o.inlet }.run()

val in1 = Source(List("a", "b", "c", "d")) val in2 = Source(List("e", "f"))

val out = Sink.publisher[String]

Page 77: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams: Graphs

val p: Publisher[String] = FlowGraph.closed(out) { implicit b ⇒ o ⇒ val merge = b.add(new StrictRoundRobin[String])

in1 ~> merge.in(0) in2 ~> merge.in(1) merge.out ~> o.inlet }.run()

val in1 = Source(List("a", "b", "c", "d")) val in2 = Source(List("e", "f"))

val out = Sink.publisher[String]

Sink[String, Publisher[String]]

imports Graphs

Page 78: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams: Graphs

val p: Publisher[String] = FlowGraph.closed(out) { implicit b ⇒ o ⇒ val merge = b.add(new StrictRoundRobin[String])

in1 ~> merge.in(0) in2 ~> merge.in(1) merge.out ~> o.inlet }.run()

val in1 = Source(List("a", "b", "c", "d")) val in2 = Source(List("e", "f"))

val out = Sink.publisher[String]

Sink[String, Publisher[String]]

materializes a Publisher[String]

Page 79: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams: Partial Graphs FlowGraph.partial() { implicit b ⇒ import FlowGraph.Implicits._

val priorityMerge = b.add(MergePreferred[In](1)) val balance = b.add(Balance[In](workerCount)) val resultsMerge = b.add(Merge[Out](workerCount))

// After merging priority and ordinary jobs, we feed them to the balancer priorityMerge ~> balance

// Wire up each of the outputs of the balancer to a worker flow // then merge them back for (i <- 0 until workerCount) balance.out(i) ~> worker ~> resultsMerge.in(i)

// We now expose the input ports of the priorityMerge and the output // of the resultsMerge as our PriorityWorkerPool ports // -- all neatly wrapped in our domain specific Shape PriorityWorkerPoolShape( jobsIn = priorityMerge.in(0), priorityJobsIn = priorityMerge.preferred, resultsOut = resultsMerge.out) }

Page 80: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams: Partial Graphs FlowGraph.partial() { implicit b ⇒ import FlowGraph.Implicits._

val priorityMerge = b.add(MergePreferred[In](1)) val balance = b.add(Balance[In](workerCount)) val resultsMerge = b.add(Merge[Out](workerCount))

// After merging priority and ordinary jobs, we feed them to the balancer priorityMerge ~> balance

// Wire up each of the outputs of the balancer to a worker flow // then merge them back for (i <- 0 until workerCount) balance.out(i) ~> worker ~> resultsMerge.in(i)

// We now expose the input ports of the priorityMerge and the output // of the resultsMerge as our PriorityWorkerPool ports // -- all neatly wrapped in our domain specific Shape PriorityWorkerPoolShape( jobsIn = priorityMerge.in(0), priorityJobsIn = priorityMerge.preferred, resultsOut = resultsMerge.out) }

Page 81: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams: Partial Graphs FlowGraph.partial() { implicit b ⇒ import FlowGraph.Implicits._

val priorityMerge = b.add(MergePreferred[In](1)) val balance = b.add(Balance[In](workerCount)) val resultsMerge = b.add(Merge[Out](workerCount))

// After merging priority and ordinary jobs, we feed them to the balancer priorityMerge ~> balance

// Wire up each of the outputs of the balancer to a worker flow // then merge them back for (i <- 0 until workerCount) balance.out(i) ~> worker ~> resultsMerge.in(i)

// We now expose the input ports of the priorityMerge and the output // of the resultsMerge as our PriorityWorkerPool ports // -- all neatly wrapped in our domain specific Shape PriorityWorkerPoolShape( jobsIn = priorityMerge.in(0), priorityJobsIn = priorityMerge.preferred, resultsOut = resultsMerge.out) }

case class PriorityWorkerPoolShape[In, Out]( jobsIn: Inlet[In], priorityJobsIn: Inlet[In], resultsOut: Outlet[Out]) extends Shape { // …

Page 82: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams: Partial Graphs

val worker1 = Flow[String].map("step 1 " + _) val worker2 = Flow[String].map("step 2 " + _)

FlowGraph.closed() { implicit b => import FlowGraph.Implicits._

val priorityPool1 = b.add(PriorityWorkerPool(worker1, 4)) val priorityPool2 = b.add(PriorityWorkerPool(worker2, 2))

Source(1 to 100).map("job: " + _) ~> priorityPool1.jobsIn Source(1 to 100).map("priority job: " + _) ~> priorityPool1.priorityJobsIn

priorityPool1.resultsOut ~> priorityPool2.jobsIn Source(1 to 100).map("one-step, priority " + _) ~> priorityPool2.priorityJobsIn

priorityPool2.resultsOut ~> Sink.foreach(println) }.run()

Page 83: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Akka Streams: Partial Graphs

val worker1 = Flow[String].map("step 1 " + _) val worker2 = Flow[String].map("step 2 " + _)

FlowGraph.closed() { implicit b => import FlowGraph.Implicits._

val priorityPool1 = b.add(PriorityWorkerPool(worker1, 4)) val priorityPool2 = b.add(PriorityWorkerPool(worker2, 2))

Source(1 to 100).map("job: " + _) ~> priorityPool1.jobsIn Source(1 to 100).map("priority job: " + _) ~> priorityPool1.priorityJobsIn

priorityPool1.resultsOut ~> priorityPool2.jobsIn Source(1 to 100).map("one-step, priority " + _) ~> priorityPool2.priorityJobsIn

priorityPool2.resultsOut ~> Sink.foreach(println) }.run()

Page 84: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Real life example: Akka Http OutgoingConnection

requestIn +----------+ +-----------------------------------------------+--->| Termi- | requestRendering | | nation +---------------------> | +-------------------------------------->| Merge | | | Termination Backchannel | +----------+ | TCP- | | | level | | Method | client | +------------+ | Bypass | flow responseOut | responsePrep | Response |<---+ | <------------+----------------| Parsing | | | Merge |<------------------------------------------ V +------------+

akka.http.engine.client.OutgoingConnectionBlueprint.scala#L47

Page 85: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Reactive StreamsBigger than Scala-ecosystem - JDK-wide (and wider).

Inter-operable back-pressure protocol.

Future work: reactive-streams-io, reactive-streams-js

Akka Streams - one of the leading Reactive Streams impls. Complex in-memory stream processing.

Akka Http - Akka Streams based, the “Spray 2.0”

Page 86: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Wrapping up

Page 87: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Wrapping upThe future is typed!

More typesafety / perf / features coming in future releases.

It’s not “just typesafety”, it’s profoundly better ways to model things.

Static stream processing graph layouts = more constraints => better ways to optimise.

Page 88: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Timing

ALL DATES ARE SUBJECT TO CHANGE. It’s done “when it’s done.”

Page 89: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

Timing

Reactive Streams - 1.0-RC5 yesterday, 1.0 in “weeks”

Akka Streams – 1.0-RC1 in around 2 weeks

Akka Http – 1.0-M6 in around 2 weeks

Akka Typed – merged as draft + experimental in Akka 2.4.x

Akka Persistence – new “read side” will use Akka Streams

ALL DATES ARE SUBJECT TO CHANGE. It’s done “when it’s done.”

Page 90: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

ktoso @ typesafe.com twitter: ktosopl

github: ktosoteam blog: letitcrash.com

home: akka.io

Thanks! / Questions?

Page 91: Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams

©Typesafe 2015 – All Rights Reserved