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
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
Top Related