format source with scalafmt
This commit is contained in:
parent
0f40491d42
commit
ce404e4f53
1669 changed files with 43208 additions and 35404 deletions
|
|
@ -19,11 +19,13 @@ class RecipeAdhocSource extends RecipeSpec {
|
|||
//#adhoc-source
|
||||
def adhocSource[T](source: Source[T, _], timeout: FiniteDuration, maxRetries: Int): Source[T, _] =
|
||||
Source.lazily(
|
||||
() => source.backpressureTimeout(timeout).recoverWithRetries(maxRetries, {
|
||||
case t: TimeoutException =>
|
||||
Source.lazily(() => source.backpressureTimeout(timeout)).mapMaterializedValue(_ => NotUsed)
|
||||
})
|
||||
)
|
||||
() =>
|
||||
source
|
||||
.backpressureTimeout(timeout)
|
||||
.recoverWithRetries(maxRetries, {
|
||||
case t: TimeoutException =>
|
||||
Source.lazily(() => source.backpressureTimeout(timeout)).mapMaterializedValue(_ => NotUsed)
|
||||
}))
|
||||
//#adhoc-source
|
||||
|
||||
"Recipe for adhoc source" must {
|
||||
|
|
@ -36,18 +38,15 @@ class RecipeAdhocSource extends RecipeSpec {
|
|||
}
|
||||
|
||||
"start the source when there is a demand" taggedAs TimingTest in {
|
||||
val sink = adhocSource(Source.repeat("a"), 200.milliseconds, 3)
|
||||
.runWith(TestSink.probe[String])
|
||||
val sink = adhocSource(Source.repeat("a"), 200.milliseconds, 3).runWith(TestSink.probe[String])
|
||||
sink.requestNext("a")
|
||||
}
|
||||
|
||||
"shut down the source when the next demand times out" taggedAs TimingTest in {
|
||||
val shutdown = Promise[Done]()
|
||||
val sink = adhocSource(
|
||||
Source.repeat("a").watchTermination() { (_, term) =>
|
||||
shutdown.completeWith(term)
|
||||
}, 200.milliseconds, 3)
|
||||
.runWith(TestSink.probe[String])
|
||||
val sink = adhocSource(Source.repeat("a").watchTermination() { (_, term) =>
|
||||
shutdown.completeWith(term)
|
||||
}, 200.milliseconds, 3).runWith(TestSink.probe[String])
|
||||
|
||||
sink.requestNext("a")
|
||||
Thread.sleep(200)
|
||||
|
|
@ -56,11 +55,9 @@ class RecipeAdhocSource extends RecipeSpec {
|
|||
|
||||
"not shut down the source when there are still demands" taggedAs TimingTest in {
|
||||
val shutdown = Promise[Done]()
|
||||
val sink = adhocSource(
|
||||
Source.repeat("a").watchTermination() { (_, term) =>
|
||||
shutdown.completeWith(term)
|
||||
}, 200.milliseconds, 3)
|
||||
.runWith(TestSink.probe[String])
|
||||
val sink = adhocSource(Source.repeat("a").watchTermination() { (_, term) =>
|
||||
shutdown.completeWith(term)
|
||||
}, 200.milliseconds, 3).runWith(TestSink.probe[String])
|
||||
|
||||
sink.requestNext("a")
|
||||
Thread.sleep(100)
|
||||
|
|
@ -80,14 +77,11 @@ class RecipeAdhocSource extends RecipeSpec {
|
|||
val shutdown = Promise[Done]()
|
||||
val startedCount = new AtomicInteger(0)
|
||||
|
||||
val source = Source
|
||||
.empty.mapMaterializedValue(_ => startedCount.incrementAndGet())
|
||||
.concat(Source.repeat("a"))
|
||||
val source = Source.empty.mapMaterializedValue(_ => startedCount.incrementAndGet()).concat(Source.repeat("a"))
|
||||
|
||||
val sink = adhocSource(source.watchTermination() { (_, term) =>
|
||||
shutdown.completeWith(term)
|
||||
}, 200.milliseconds, 3)
|
||||
.runWith(TestSink.probe[String])
|
||||
}, 200.milliseconds, 3).runWith(TestSink.probe[String])
|
||||
|
||||
sink.requestNext("a")
|
||||
startedCount.get() should be(1)
|
||||
|
|
@ -99,14 +93,11 @@ class RecipeAdhocSource extends RecipeSpec {
|
|||
val shutdown = Promise[Done]()
|
||||
val startedCount = new AtomicInteger(0)
|
||||
|
||||
val source = Source
|
||||
.empty.mapMaterializedValue(_ => startedCount.incrementAndGet())
|
||||
.concat(Source.repeat("a"))
|
||||
val source = Source.empty.mapMaterializedValue(_ => startedCount.incrementAndGet()).concat(Source.repeat("a"))
|
||||
|
||||
val sink = adhocSource(source.watchTermination() { (_, term) =>
|
||||
shutdown.completeWith(term)
|
||||
}, 200.milliseconds, 3)
|
||||
.runWith(TestSink.probe[String])
|
||||
}, 200.milliseconds, 3).runWith(TestSink.probe[String])
|
||||
|
||||
sink.requestNext("a")
|
||||
startedCount.get() should be(1)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
package docs.stream.cookbook
|
||||
|
||||
import akka.NotUsed
|
||||
import akka.stream.{ Attributes, Outlet, Inlet, FlowShape }
|
||||
import akka.stream.{ Attributes, FlowShape, Inlet, Outlet }
|
||||
import akka.stream.scaladsl.{ Flow, Sink, Source }
|
||||
import akka.util.ByteString
|
||||
|
||||
|
|
@ -35,26 +35,27 @@ class RecipeByteStrings extends RecipeSpec {
|
|||
emitChunk()
|
||||
}
|
||||
})
|
||||
setHandler(in, new InHandler {
|
||||
override def onPush(): Unit = {
|
||||
val elem = grab(in)
|
||||
buffer ++= elem
|
||||
emitChunk()
|
||||
}
|
||||
setHandler(in,
|
||||
new InHandler {
|
||||
override def onPush(): Unit = {
|
||||
val elem = grab(in)
|
||||
buffer ++= elem
|
||||
emitChunk()
|
||||
}
|
||||
|
||||
override def onUpstreamFinish(): Unit = {
|
||||
if (buffer.isEmpty) completeStage()
|
||||
else {
|
||||
// There are elements left in buffer, so
|
||||
// we keep accepting downstream pulls and push from buffer until emptied.
|
||||
//
|
||||
// It might be though, that the upstream finished while it was pulled, in which
|
||||
// case we will not get an onPull from the downstream, because we already had one.
|
||||
// In that case we need to emit from the buffer.
|
||||
if (isAvailable(out)) emitChunk()
|
||||
}
|
||||
}
|
||||
})
|
||||
override def onUpstreamFinish(): Unit = {
|
||||
if (buffer.isEmpty) completeStage()
|
||||
else {
|
||||
// There are elements left in buffer, so
|
||||
// we keep accepting downstream pulls and push from buffer until emptied.
|
||||
//
|
||||
// It might be though, that the upstream finished while it was pulled, in which
|
||||
// case we will not get an onPull from the downstream, because we already had one.
|
||||
// In that case we need to emit from the buffer.
|
||||
if (isAvailable(out)) emitChunk()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
private def emitChunk(): Unit = {
|
||||
if (buffer.isEmpty) {
|
||||
|
|
@ -92,19 +93,21 @@ class RecipeByteStrings extends RecipeSpec {
|
|||
override def createLogic(inheritedAttributes: Attributes): GraphStageLogic = new GraphStageLogic(shape) {
|
||||
private var count = 0
|
||||
|
||||
setHandlers(in, out, new InHandler with OutHandler {
|
||||
setHandlers(in,
|
||||
out,
|
||||
new InHandler with OutHandler {
|
||||
|
||||
override def onPull(): Unit = {
|
||||
pull(in)
|
||||
}
|
||||
override def onPull(): Unit = {
|
||||
pull(in)
|
||||
}
|
||||
|
||||
override def onPush(): Unit = {
|
||||
val chunk = grab(in)
|
||||
count += chunk.size
|
||||
if (count > maximumBytes) failStage(new IllegalStateException("Too much bytes"))
|
||||
else push(out, chunk)
|
||||
}
|
||||
})
|
||||
override def onPush(): Unit = {
|
||||
val chunk = grab(in)
|
||||
count += chunk.size
|
||||
if (count > maximumBytes) failStage(new IllegalStateException("Too much bytes"))
|
||||
else push(out, chunk)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -114,8 +117,8 @@ class RecipeByteStrings extends RecipeSpec {
|
|||
val bytes1 = Source(List(ByteString(1, 2), ByteString(3), ByteString(4, 5, 6), ByteString(7, 8, 9)))
|
||||
val bytes2 = Source(List(ByteString(1, 2), ByteString(3), ByteString(4, 5, 6), ByteString(7, 8, 9, 10)))
|
||||
|
||||
Await.result(bytes1.via(limiter).limit(10).runWith(Sink.seq), 3.seconds)
|
||||
.fold(ByteString.empty)(_ ++ _) should be(ByteString(1, 2, 3, 4, 5, 6, 7, 8, 9))
|
||||
Await.result(bytes1.via(limiter).limit(10).runWith(Sink.seq), 3.seconds).fold(ByteString.empty)(_ ++ _) should be(
|
||||
ByteString(1, 2, 3, 4, 5, 6, 7, 8, 9))
|
||||
|
||||
an[IllegalStateException] must be thrownBy {
|
||||
Await.result(bytes2.via(limiter).limit(10).runWith(Sink.seq), 3.seconds)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package docs.stream.cookbook
|
||||
|
||||
import akka.stream.{ ActorMaterializerSettings, ActorMaterializer }
|
||||
import akka.stream.{ ActorMaterializer, ActorMaterializerSettings }
|
||||
|
||||
import scala.collection.immutable
|
||||
import scala.concurrent.Await
|
||||
|
|
|
|||
|
|
@ -19,12 +19,10 @@ class RecipeDecompress extends RecipeSpec {
|
|||
//#decompress-gzip
|
||||
|
||||
val compressed =
|
||||
Source.single(ByteString.fromString("Hello World"))
|
||||
.via(Compression.gzip)
|
||||
Source.single(ByteString.fromString("Hello World")).via(Compression.gzip)
|
||||
|
||||
//#decompress-gzip
|
||||
val uncompressed = compressed.via(Compression.gunzip())
|
||||
.map(_.utf8String)
|
||||
val uncompressed = compressed.via(Compression.gunzip()).map(_.utf8String)
|
||||
//#decompress-gzip
|
||||
|
||||
Await.result(uncompressed.runWith(Sink.head), 3.seconds) should be("Hello World")
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class RecipeDigest extends RecipeSpec {
|
|||
import java.security.MessageDigest
|
||||
|
||||
import akka.NotUsed
|
||||
import akka.stream.{ Attributes, Outlet, Inlet, FlowShape }
|
||||
import akka.stream.{ Attributes, FlowShape, Inlet, Outlet }
|
||||
import akka.stream.scaladsl.{ Sink, Source }
|
||||
import akka.util.ByteString
|
||||
|
||||
|
|
@ -56,15 +56,8 @@ class RecipeDigest extends RecipeSpec {
|
|||
//#calculating-digest
|
||||
|
||||
Await.result(digest.runWith(Sink.head), 3.seconds) should be(
|
||||
ByteString(
|
||||
0xba, 0x78, 0x16, 0xbf,
|
||||
0x8f, 0x01, 0xcf, 0xea,
|
||||
0x41, 0x41, 0x40, 0xde,
|
||||
0x5d, 0xae, 0x22, 0x23,
|
||||
0xb0, 0x03, 0x61, 0xa3,
|
||||
0x96, 0x17, 0x7a, 0x9c,
|
||||
0xb4, 0x10, 0xff, 0x61,
|
||||
0xf2, 0x00, 0x15, 0xad))
|
||||
ByteString(0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0,
|
||||
0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,16 +24,17 @@ class RecipeDroppyBroadcast extends RecipeSpec {
|
|||
val mySink3 = Sink.fromSubscriber(sub3)
|
||||
|
||||
//#droppy-bcast
|
||||
val graph = RunnableGraph.fromGraph(GraphDSL.create(mySink1, mySink2, mySink3)((_, _, _)) { implicit b => (sink1, sink2, sink3) =>
|
||||
import GraphDSL.Implicits._
|
||||
val graph = RunnableGraph.fromGraph(GraphDSL.create(mySink1, mySink2, mySink3)((_, _, _)) {
|
||||
implicit b => (sink1, sink2, sink3) =>
|
||||
import GraphDSL.Implicits._
|
||||
|
||||
val bcast = b.add(Broadcast[Int](3))
|
||||
myElements ~> bcast
|
||||
val bcast = b.add(Broadcast[Int](3))
|
||||
myElements ~> bcast
|
||||
|
||||
bcast.buffer(10, OverflowStrategy.dropHead) ~> sink1
|
||||
bcast.buffer(10, OverflowStrategy.dropHead) ~> sink2
|
||||
bcast.buffer(10, OverflowStrategy.dropHead) ~> sink3
|
||||
ClosedShape
|
||||
bcast.buffer(10, OverflowStrategy.dropHead) ~> sink1
|
||||
bcast.buffer(10, OverflowStrategy.dropHead) ~> sink2
|
||||
bcast.buffer(10, OverflowStrategy.dropHead) ~> sink3
|
||||
ClosedShape
|
||||
})
|
||||
//#droppy-bcast
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
package docs.stream.cookbook
|
||||
|
||||
import akka.NotUsed
|
||||
import akka.actor.{ Props, ActorRef, Actor }
|
||||
import akka.actor.{ Actor, ActorRef, Props }
|
||||
import akka.stream.ClosedShape
|
||||
import akka.stream.scaladsl._
|
||||
import akka.stream.testkit._
|
||||
|
|
@ -25,26 +25,22 @@ class RecipeGlobalRateLimit extends RecipeSpec {
|
|||
|
||||
case object ReplenishTokens
|
||||
|
||||
def props(maxAvailableTokens: Int, tokenRefreshPeriod: FiniteDuration,
|
||||
tokenRefreshAmount: Int): Props =
|
||||
def props(maxAvailableTokens: Int, tokenRefreshPeriod: FiniteDuration, tokenRefreshAmount: Int): Props =
|
||||
Props(new Limiter(maxAvailableTokens, tokenRefreshPeriod, tokenRefreshAmount))
|
||||
}
|
||||
|
||||
class Limiter(
|
||||
val maxAvailableTokens: Int,
|
||||
val tokenRefreshPeriod: FiniteDuration,
|
||||
val tokenRefreshAmount: Int) extends Actor {
|
||||
class Limiter(val maxAvailableTokens: Int, val tokenRefreshPeriod: FiniteDuration, val tokenRefreshAmount: Int)
|
||||
extends Actor {
|
||||
import Limiter._
|
||||
import context.dispatcher
|
||||
import akka.actor.Status
|
||||
|
||||
private var waitQueue = immutable.Queue.empty[ActorRef]
|
||||
private var permitTokens = maxAvailableTokens
|
||||
private val replenishTimer = system.scheduler.schedule(
|
||||
initialDelay = tokenRefreshPeriod,
|
||||
interval = tokenRefreshPeriod,
|
||||
receiver = self,
|
||||
ReplenishTokens)
|
||||
private val replenishTimer = system.scheduler.schedule(initialDelay = tokenRefreshPeriod,
|
||||
interval = tokenRefreshPeriod,
|
||||
receiver = self,
|
||||
ReplenishTokens)
|
||||
|
||||
override def receive: Receive = open
|
||||
|
||||
|
|
@ -69,13 +65,13 @@ class RecipeGlobalRateLimit extends RecipeSpec {
|
|||
val (toBeReleased, remainingQueue) = waitQueue.splitAt(permitTokens)
|
||||
waitQueue = remainingQueue
|
||||
permitTokens -= toBeReleased.size
|
||||
toBeReleased foreach (_ ! MayPass)
|
||||
toBeReleased.foreach(_ ! MayPass)
|
||||
if (permitTokens > 0) context.become(open)
|
||||
}
|
||||
|
||||
override def postStop(): Unit = {
|
||||
replenishTimer.cancel()
|
||||
waitQueue foreach (_ ! Status.Failure(new IllegalStateException("limiter stopped")))
|
||||
waitQueue.foreach(_ ! Status.Failure(new IllegalStateException("limiter stopped")))
|
||||
}
|
||||
}
|
||||
//#global-limiter-actor
|
||||
|
|
@ -104,13 +100,15 @@ class RecipeGlobalRateLimit extends RecipeSpec {
|
|||
|
||||
val probe = TestSubscriber.manualProbe[String]()
|
||||
|
||||
RunnableGraph.fromGraph(GraphDSL.create() { implicit b =>
|
||||
import GraphDSL.Implicits._
|
||||
val merge = b.add(Merge[String](2))
|
||||
source1 ~> merge ~> Sink.fromSubscriber(probe)
|
||||
source2 ~> merge
|
||||
ClosedShape
|
||||
}).run()
|
||||
RunnableGraph
|
||||
.fromGraph(GraphDSL.create() { implicit b =>
|
||||
import GraphDSL.Implicits._
|
||||
val merge = b.add(Merge[String](2))
|
||||
source1 ~> merge ~> Sink.fromSubscriber(probe)
|
||||
source2 ~> merge
|
||||
ClosedShape
|
||||
})
|
||||
.run()
|
||||
|
||||
probe.expectSubscription().request(1000)
|
||||
|
||||
|
|
|
|||
|
|
@ -55,20 +55,22 @@ object HoldOps {
|
|||
private var currentValue: T = _
|
||||
private var waitingFirstValue = true
|
||||
|
||||
setHandlers(in, out, new InHandler with OutHandler {
|
||||
override def onPush(): Unit = {
|
||||
currentValue = grab(in)
|
||||
if (waitingFirstValue) {
|
||||
waitingFirstValue = false
|
||||
if (isAvailable(out)) push(out, currentValue)
|
||||
}
|
||||
pull(in)
|
||||
}
|
||||
setHandlers(in,
|
||||
out,
|
||||
new InHandler with OutHandler {
|
||||
override def onPush(): Unit = {
|
||||
currentValue = grab(in)
|
||||
if (waitingFirstValue) {
|
||||
waitingFirstValue = false
|
||||
if (isAvailable(out)) push(out, currentValue)
|
||||
}
|
||||
pull(in)
|
||||
}
|
||||
|
||||
override def onPull(): Unit = {
|
||||
if (!waitingFirstValue) push(out, currentValue)
|
||||
}
|
||||
})
|
||||
override def onPull(): Unit = {
|
||||
if (!waitingFirstValue) push(out, currentValue)
|
||||
}
|
||||
})
|
||||
|
||||
override def preStart(): Unit = {
|
||||
pull(in)
|
||||
|
|
@ -90,9 +92,7 @@ class RecipeHold extends RecipeSpec {
|
|||
val source = Source.fromPublisher(pub)
|
||||
val sink = Sink.fromSubscriber(sub)
|
||||
|
||||
source.via(new HoldWithInitial(0)).to(sink)
|
||||
.withAttributes(Attributes.inputBuffer(1, 1))
|
||||
.run()
|
||||
source.via(new HoldWithInitial(0)).to(sink).withAttributes(Attributes.inputBuffer(1, 1)).run()
|
||||
|
||||
val subscription = sub.expectSubscription()
|
||||
sub.expectNoMessage(100.millis)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ class RecipeLoggingElements extends RecipeSpec {
|
|||
val mySource = Source(List("1", "2", "3"))
|
||||
|
||||
//#println-debug
|
||||
val loggedSource = mySource.map { elem => println(elem); elem }
|
||||
val loggedSource = mySource.map { elem =>
|
||||
println(elem); elem
|
||||
}
|
||||
//#println-debug
|
||||
|
||||
loggedSource.runWith(Sink.ignore)
|
||||
|
|
@ -33,14 +35,10 @@ class RecipeLoggingElements extends RecipeSpec {
|
|||
|
||||
//#log-custom
|
||||
// customise log levels
|
||||
mySource.log("before-map")
|
||||
.withAttributes(
|
||||
Attributes.logLevels(
|
||||
onElement = Logging.WarningLevel,
|
||||
onFinish = Logging.InfoLevel,
|
||||
onFailure = Logging.DebugLevel
|
||||
)
|
||||
)
|
||||
mySource
|
||||
.log("before-map")
|
||||
.withAttributes(Attributes
|
||||
.logLevels(onElement = Logging.WarningLevel, onFinish = Logging.InfoLevel, onFailure = Logging.DebugLevel))
|
||||
.map(analyse)
|
||||
|
||||
// or provide custom logging adapter
|
||||
|
|
|
|||
|
|
@ -25,13 +25,11 @@ class RecipeMissedTicks extends RecipeSpec {
|
|||
|
||||
//#missed-ticks
|
||||
val missedTicks: Flow[Tick, Int, NotUsed] =
|
||||
Flow[Tick].conflateWithSeed(seed = (_) => 0)(
|
||||
(missedTicks, tick) => missedTicks + 1)
|
||||
Flow[Tick].conflateWithSeed(seed = (_) => 0)((missedTicks, tick) => missedTicks + 1)
|
||||
//#missed-ticks
|
||||
val latch = TestLatch(3)
|
||||
val realMissedTicks: Flow[Tick, Int, NotUsed] =
|
||||
Flow[Tick].conflateWithSeed(seed = (_) => 0)(
|
||||
(missedTicks, tick) => { latch.countDown(); missedTicks + 1 })
|
||||
Flow[Tick].conflateWithSeed(seed = (_) => 0)((missedTicks, tick) => { latch.countDown(); missedTicks + 1 })
|
||||
|
||||
tickStream.via(realMissedTicks).to(sink).run()
|
||||
|
||||
|
|
|
|||
|
|
@ -35,14 +35,13 @@ class RecipeMultiGroupBy extends RecipeSpec {
|
|||
topicsForMessage.map(msg -> _)
|
||||
}
|
||||
|
||||
val multiGroups = messageAndTopic
|
||||
.groupBy(2, _._2).map {
|
||||
case (msg, topic) =>
|
||||
// do what needs to be done
|
||||
//#multi-groupby
|
||||
(msg, topic)
|
||||
val multiGroups = messageAndTopic.groupBy(2, _._2).map {
|
||||
case (msg, topic) =>
|
||||
// do what needs to be done
|
||||
//#multi-groupby
|
||||
}
|
||||
(msg, topic)
|
||||
//#multi-groupby
|
||||
}
|
||||
//#multi-groupby
|
||||
|
||||
val result = multiGroups
|
||||
|
|
@ -52,9 +51,7 @@ class RecipeMultiGroupBy extends RecipeSpec {
|
|||
.limit(10)
|
||||
.runWith(Sink.seq)
|
||||
|
||||
Await.result(result, 3.seconds).toSet should be(Set(
|
||||
"1[1: a, 1: b, all: c, all: d, 1: e]",
|
||||
"2[all: c, all: d]"))
|
||||
Await.result(result, 3.seconds).toSet should be(Set("1[1: a, 1: b, all: c, all: d, 1: e]", "2[all: c, all: d]"))
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,25 +16,22 @@ class RecipeParseLines extends RecipeSpec {
|
|||
"Recipe for parsing line from bytes" must {
|
||||
|
||||
"work" in {
|
||||
val rawData = Source(List(
|
||||
ByteString("Hello World"),
|
||||
ByteString("\r"),
|
||||
ByteString("!\r"),
|
||||
ByteString("\nHello Akka!\r\nHello Streams!"),
|
||||
ByteString("\r\n\r\n")))
|
||||
val rawData = Source(
|
||||
List(ByteString("Hello World"),
|
||||
ByteString("\r"),
|
||||
ByteString("!\r"),
|
||||
ByteString("\nHello Akka!\r\nHello Streams!"),
|
||||
ByteString("\r\n\r\n")))
|
||||
|
||||
//#parse-lines
|
||||
import akka.stream.scaladsl.Framing
|
||||
val linesStream = rawData.via(Framing.delimiter(
|
||||
ByteString("\r\n"), maximumFrameLength = 100, allowTruncation = true))
|
||||
val linesStream = rawData
|
||||
.via(Framing.delimiter(ByteString("\r\n"), maximumFrameLength = 100, allowTruncation = true))
|
||||
.map(_.utf8String)
|
||||
//#parse-lines
|
||||
|
||||
Await.result(linesStream.limit(10).runWith(Sink.seq), 3.seconds) should be(List(
|
||||
"Hello World\r!",
|
||||
"Hello Akka!",
|
||||
"Hello Streams!",
|
||||
""))
|
||||
Await.result(linesStream.limit(10).runWith(Sink.seq), 3.seconds) should be(
|
||||
List("Hello World\r!", "Hello Akka!", "Hello Streams!", ""))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class RecipeReduceByKey extends RecipeSpec {
|
|||
|
||||
//#word-count
|
||||
val counts: Source[(String, Int), NotUsed] = words
|
||||
// split the words into separate streams first
|
||||
// split the words into separate streams first
|
||||
.groupBy(MaximumDistinctWords, identity)
|
||||
//transform each element to pair with number of words in it
|
||||
.map(_ -> 1)
|
||||
|
|
@ -31,13 +31,8 @@ class RecipeReduceByKey extends RecipeSpec {
|
|||
.mergeSubstreams
|
||||
//#word-count
|
||||
|
||||
Await.result(counts.limit(10).runWith(Sink.seq), 3.seconds).toSet should be(Set(
|
||||
("hello", 2),
|
||||
("world", 1),
|
||||
("and", 1),
|
||||
("universe", 1),
|
||||
("akka", 1),
|
||||
("rocks!", 1000)))
|
||||
Await.result(counts.limit(10).runWith(Sink.seq), 3.seconds).toSet should be(
|
||||
Set(("hello", 2), ("world", 1), ("and", 1), ("universe", 1), ("akka", 1), ("rocks!", 1000)))
|
||||
}
|
||||
|
||||
"work generalized" in {
|
||||
|
|
@ -45,10 +40,9 @@ class RecipeReduceByKey extends RecipeSpec {
|
|||
def words = Source(List("hello", "world", "and", "hello", "universe", "akka") ++ List.fill(1000)("rocks!"))
|
||||
|
||||
//#reduce-by-key-general
|
||||
def reduceByKey[In, K, Out](
|
||||
maximumGroupSize: Int,
|
||||
groupKey: (In) => K,
|
||||
map: (In) => Out)(reduce: (Out, Out) => Out): Flow[In, (K, Out), NotUsed] = {
|
||||
def reduceByKey[In, K, Out](maximumGroupSize: Int,
|
||||
groupKey: (In) => K,
|
||||
map: (In) => Out)(reduce: (Out, Out) => Out): Flow[In, (K, Out), NotUsed] = {
|
||||
|
||||
Flow[In]
|
||||
.groupBy[K](maximumGroupSize, groupKey)
|
||||
|
|
@ -58,19 +52,12 @@ class RecipeReduceByKey extends RecipeSpec {
|
|||
}
|
||||
|
||||
val wordCounts = words.via(
|
||||
reduceByKey(
|
||||
MaximumDistinctWords,
|
||||
groupKey = (word: String) => word,
|
||||
map = (word: String) => 1)((left: Int, right: Int) => left + right))
|
||||
reduceByKey(MaximumDistinctWords, groupKey = (word: String) => word, map = (word: String) => 1)(
|
||||
(left: Int, right: Int) => left + right))
|
||||
//#reduce-by-key-general
|
||||
|
||||
Await.result(wordCounts.limit(10).runWith(Sink.seq), 3.seconds).toSet should be(Set(
|
||||
("hello", 2),
|
||||
("world", 1),
|
||||
("and", 1),
|
||||
("universe", 1),
|
||||
("akka", 1),
|
||||
("rocks!", 1000)))
|
||||
Await.result(wordCounts.limit(10).runWith(Sink.seq), 3.seconds).toSet should be(
|
||||
Set(("hello", 2), ("world", 1), ("and", 1), ("universe", 1), ("akka", 1), ("rocks!", 1000)))
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ class RecipeWorkerPool extends RecipeSpec {
|
|||
val processedJobs: Source[Result, NotUsed] = myJobs.via(balancer(worker, 3))
|
||||
//#worker-pool
|
||||
|
||||
Await.result(processedJobs.limit(10).runWith(Sink.seq), 3.seconds).toSet should be(Set(
|
||||
"1 done", "2 done", "3 done", "4 done", "5 done"))
|
||||
Await.result(processedJobs.limit(10).runWith(Sink.seq), 3.seconds).toSet should be(
|
||||
Set("1 done", "2 done", "3 done", "4 done", "5 done"))
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue