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

Post on 16-Jul-2015

404 views 0 download

Tags:

Transcript of 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

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

Konrad `@ktosopl` Malawski

Fresh from the Oven - akka gets Typed

Konrad `ktoso` Malawski

Akka Team, Reactive Streams TCK

Konrad `@ktosopl` Malawski

akka.iotypesafe.comgeecon.org

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

GDGKrakow.pl lambdakrk.pl

Nice to meet you! Who are you guys?

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!

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

Akka Actors

Akka Actors“untyped”

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

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).

Akka Typed

Akka Typed

NOT the Old Typed Actors module

Akka TypedNOT the Old Typed Actors module

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.

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.

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.

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

Akka Typed

Akka Typed is primarily the work of Dr Roland Kuhn

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

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

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!

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.

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.

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!

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])

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!

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)

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)

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)

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.

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

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

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 // ...}

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”

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:

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)

Akka Typed

Reactive Streams

Reactive StreamsAkka Streams

Reactive Streams

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

Reactive 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 …

What is back-pressure?

Back-pressure?

Back-pressure? WAT!

Back-pressure? WAT!

What if the buffer overflows?

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

Use bounded buffer, drop messages + require re-sending

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

Kernel does this!Routers do this!

(TCP)

Use bounded buffer, drop messages + require re-sending

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

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

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

Back-pressure?Reactive-Streams

= “Dynamic Push/Pull”

Just push – not safe when Slow Subscriber

Just pull – too slow when Fast Subscriber

Back-pressure? RS: Dynamic Push/Pull

Solution:Dynamic adjustment

Back-pressure? RS: Dynamic Push/Pull

Just push – not safe when Slow Subscriber

Just pull – too slow when Fast Subscriber

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

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

Back-pressure? RS: Dynamic Push/Pull

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

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

Publisher can accumulate demand.

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

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

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

Back-pressure? RS: Dynamic Push/Pull

MAX

speed

Back-pressure? RS: Dynamic Push/Pull

Easy

MAX

speed

Back-pressureFile upload demo with Akka HTTP

Akka Streams – Linear Flow

Akka Streams – Linear Flow

Akka Streams – Linear Flow

Akka Streams – Linear Flow

Akka Streams – Linear Flow

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

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

Akka Streams – Linear Flow

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

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

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)

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…

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.

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.

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]]

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]

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

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]

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) }

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) }

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 { // …

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()

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()

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

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”

Wrapping up

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.

Timing

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

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.”

ktoso @ typesafe.com twitter: ktosopl

github: ktosoteam blog: letitcrash.com

home: akka.io

Thanks! / Questions?

©Typesafe 2015 – All Rights Reserved