Not all akka stream Sinks receive the emitted data - scala

When running the following akka streaming FlowGraph not all the emitted Chars are received by all Sinks.
package sample.stream
import java.io.{ FileOutputStream, PrintWriter }
import akka.actor.ActorSystem
import akka.stream.ActorFlowMaterializer
import akka.stream.scaladsl.{ Broadcast, FlowGraph, Sink, Source }
import scala.concurrent.forkjoin.ThreadLocalRandom
import scala.util.{ Failure, Success, Try }
object Sample {
def main(args: Array[String]): Unit = {
println("start")
implicit val system = ActorSystem("Sys")
import system.dispatcher
implicit val materializer = ActorFlowMaterializer()
var counter = -1
val countSource: Source[Char, Unit] = Source(() => Iterator.continually { counter += 1; (counter + 'A').toChar }.take(11))
var counter1 = 0
val consoleSink1 = Sink.foreach[Char] { counter =>
println("sink1:" + counter1 + ":" + counter)
counter1 += 1
Thread.sleep(100)
//Thread.sleep(300)
}
var counter2 = 0
val consoleSink2 = Sink.foreach[Char] { counter =>
println("sink2:" + counter2 + ":" + counter)
counter2 += 1
Thread.sleep(200)
}
val materialized = FlowGraph.closed(consoleSink1, consoleSink2)((x1, x2) => x1) { implicit builder =>
(console1, console2) =>
import FlowGraph.Implicits._
val broadcast = builder.add(Broadcast[Char](2))
countSource ~> broadcast ~> console1
broadcast ~> console2
}.run()
// ensure the output file is closed and the system shutdown upon completion
materialized.onComplete {
case Success(_) =>
system.shutdown()
case Failure(e) =>
println(s"Failure: ${e.getMessage}")
system.shutdown()
}
println("waiting the remaining ones")
//scala.concurrent.Await.ready(materialized, scala.concurrent.duration.DurationInt(100).seconds)
//system.shutdown()
println("end")
}
}
After running the following output is generated
[info] Running sample.stream.Sample
[info] start
[info] waiting the remaining ones
[info] end
[info] sink2:0:A
[info] sink1:0:A
[info] sink1:1:B
[info] sink1:2:C
[info] sink2:1:B
[info] sink1:3:D
[info] sink2:2:C
[info] sink1:4:E
[info] sink1:5:F
[info] sink2:3:D
[info] sink1:6:G
[info] sink1:7:H
[info] sink2:4:E
[info] sink2:5:F
[info] sink1:8:I
[info] sink1:9:J
[info] sink2:6:G
[info] sink2:7:H
[info] sink1:10:K
The second sink doesn't receive the 8th, 9th and 10th values: IJK but still the entire flow is ended.
What should I do to wait for both Sinks to consume all the data?
I discovered that if I change the (x1,x2)=>x1 to (x1,x2)=>x2 this will wait. That is the same with sleeping 300ms in the first sink.

The function that you pass to a second parameter list of FlowGraph.closed determines what materialized value is returned when you run the flow. So when you pass in (x1,x2)=>x1 you return a future which is completed when the first sink gets all elements and then the callback on that future shuts down the actor system without the second sink having a chance receiving all of the elements.
Instead, you should get both futures out and shutdown the system only when both futures are completed.
You can actually see how this approach is used in some of the akka-stream tests here.

Related

Why mapping a class A to class B with monix or akka-streams is so slow?

I've benchmarked the mapping of a List[ClassA] to List[ClassB] with monix and akka-streams but I don't understand why it is so slow.
I've tried different way to map and here is the result with JMH:
[info] Benchmark Mode Cnt Score Error Units
[info] MappingBenchmark.akkaLoadBalanceMap ss 20 742,626 â–’ 4,853 ms/op
[info] MappingBenchmark.akkaMapAsyncFold ss 20 480,460 â–’ 8,493 ms/op
[info] MappingBenchmark.akkaMapAsyncFoldAsync ss 20 331,398 â–’ 10,490 ms/op
[info] MappingBenchmark.akkaMapFold ss 20 713,500 â–’ 7,394 ms/op
[info] MappingBenchmark.akkaMapFoldAsync ss 20 313,275 â–’ 8,716 ms/op
[info] MappingBenchmark.map ss 20 0,567 â–’ 0,175 ms/op
[info] MappingBenchmark.monixBatchedObservables ss 20 259,736 â–’ 5,939 ms/op
[info] MappingBenchmark.monixMapAsyncFoldLeft ss 20 456,310 â–’ 5,225 ms/op
[info] MappingBenchmark.monixMapAsyncFoldLeftAsync ss 20 795,345 â–’ 5,443 ms/op
[info] MappingBenchmark.monixMapFoldLeft ss 20 247,172 â–’ 5,342 ms/op
[info] MappingBenchmark.monixMapFoldLeftAsync ss 20 478,840 â–’ 25,249 ms/op
[info] MappingBenchmark.monixTaskGather ss 20 6,707 â–’ 2,176 ms/op
[info] MappingBenchmark.parMap ss 20 1,257 â–’ 0,831 ms/op
Here is the code:
package benches
import java.util.concurrent.TimeUnit
import akka.NotUsed
import akka.actor.ActorSystem
import akka.stream.{ActorMaterializer, ClosedShape, UniformFanInShape, UniformFanOutShape}
import akka.stream.scaladsl.{Balance, Flow, GraphDSL, Keep, Merge, RunnableGraph, Sink, Source}
import org.openjdk.jmh.annotations._
import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
#OutputTimeUnit(TimeUnit.MILLISECONDS)
#BenchmarkMode(Array(Mode.SingleShotTime))
#Warmup(iterations = 20)
#Measurement(iterations = 20)
#Fork(value = 1, jvmArgs = Array("-server", "-Xmx8g"))
#Threads(1)
class MappingBenchmark {
import monix.eval._
import monix.reactive._
import monix.execution.Scheduler.Implicits.global
def list: List[ClassA] = (1 to 10000).map(ClassA).toList
// val l = (1 to 135368).map(Offre).toList
// ##### SCALA ##### //
#Benchmark
def map: List[ClassB] = list.map(o => ClassB(o, o))
#Benchmark
def parMap: List[ClassB] = list.par.map(o => ClassB(o, o)).toList
// ##### MONIX ##### //
#Benchmark
def monixTaskGather: List[ClassB] = {
val task: Task[List[ClassB]] = Task.gatherUnordered(list.map(o => Task(ClassB(o,o))))
Await.result(task.runAsync, Duration.Inf)
}
#Benchmark
def monixBatchedObservables: List[ClassB] = {
val task: Task[List[ClassB]] =
Observable.fromIterable(list)
.bufferIntrospective(256)
.flatMap{items =>
val tasks = items.map(o => Task(ClassB(o,o)))
val batches = tasks.sliding(10,10).map(b => Task.gatherUnordered(b))
val aggregate: Task[Iterator[ClassB]] = Task.sequence(batches).map(_.flatten)
Observable.fromTask(aggregate).flatMap(i => Observable.fromIterator(i))
}.consumeWith(Consumer.foldLeft(List[ClassB]())(_ :+ _))
Await.result(task.runAsync, Duration.Inf)
}
#Benchmark
def monixMapFoldLeft: List[ClassB] = {
val task: Task[List[ClassB]] = Observable.fromIterable(list).map(o => ClassB(o, o)).consumeWith(Consumer.foldLeft(List[ClassB]())(_ :+ _))
Await.result(task.runAsync, Duration.Inf)
}
#Benchmark
def monixMapFoldLeftAsync: List[ClassB] = {
val task: Task[List[ClassB]] = Observable.fromIterable(list).map(o => ClassB(o, o)).consumeWith(Consumer.foldLeftAsync(List[ClassB]())((l, o) => Task(l :+ o)))
Await.result(task.runAsync, Duration.Inf)
}
#Benchmark
def monixMapAsyncFoldLeft: List[ClassB] = {
val task: Task[List[ClassB]] = Observable.fromIterable(list).mapAsync(4)(o => Task(ClassB(o, o))).consumeWith(Consumer.foldLeft(List[ClassB]())(_ :+ _))
Await.result(task.runAsync, Duration.Inf)
}
#Benchmark
def monixMapAsyncFoldLeftAsync: List[ClassB] = {
val task: Task[List[ClassB]] = Observable.fromIterable(list).mapAsync(4)(o => Task(ClassB(o, o))).consumeWith(Consumer.foldLeftAsync(List[ClassB]())((l, o) => Task(l :+ o)))
Await.result(task.runAsync, Duration.Inf)
}
// ##### AKKA-STREAM ##### //
#Benchmark
def akkaMapFold: List[ClassB] = {
val graph: RunnableGraph[Future[List[ClassB]]] = Source(list).map(o => ClassB(o,o)).toMat(Sink.fold(List[ClassB]())(_ :+ _))(Keep.right)
runAkkaGraph(graph)
}
#Benchmark
def akkaMapFoldAsync: List[ClassB] = {
val graph: RunnableGraph[Future[List[ClassB]]] = Source(list).map(o => ClassB(o,o)).toMat(Sink.foldAsync(List[ClassB]())((l, o) => Future(l :+ o)))(Keep.right)
runAkkaGraph(graph)
}
#Benchmark
def akkaMapAsyncFold: List[ClassB] = {
def graph: RunnableGraph[Future[List[ClassB]]] = Source(list).mapAsync(4)(o => Future(ClassB(o,o))).async.toMat(Sink.fold(List[ClassB]())(_ :+ _))(Keep.right)
runAkkaGraph(graph)
}
#Benchmark
def akkaMapAsyncFoldAsync: List[ClassB] = {
def graph: RunnableGraph[Future[List[ClassB]]] = Source(list).mapAsync(4)(o => Future(ClassB(o,o))).async.toMat(Sink.foldAsync(List[ClassB]())((l, o) => Future(l :+ o)))(Keep.right)
runAkkaGraph(graph)
}
#Benchmark
def akkaLoadBalanceMap: List[ClassB] = {
def graph: RunnableGraph[Future[List[ClassB]]] = {
val sink: Sink[ClassB, Future[List[ClassB]]] = Sink.fold(List[ClassB]())(_ :+ _)
RunnableGraph.fromGraph[Future[List[ClassB]]](GraphDSL.create(sink) { implicit builder =>
sink =>
import GraphDSL.Implicits._
val balance: UniformFanOutShape[ClassA, ClassA] = builder.add(Balance[ClassA](4))
val merge: UniformFanInShape[ClassB, ClassB] = builder.add(Merge[ClassB](4))
val mapClassB: Flow[ClassA, ClassB, NotUsed] = Flow[ClassA].map(o => ClassB(o,o))
Source(list) ~> balance
(1 to 4).foreach{ i =>
balance ~> mapClassB.async ~> merge
}
merge ~> sink
ClosedShape
})
}
runAkkaGraph(graph)
}
private def runAkkaGraph(g:RunnableGraph[Future[List[ClassB]]]): List[ClassB] = {
implicit val actorSystem = ActorSystem("app")
implicit val actorMaterializer = ActorMaterializer()
val eventualBs = g.run()
val res = Await.result(eventualBs, Duration.Inf)
actorSystem.terminate()
res
}
}
case class ClassA(a:Int)
case class ClassB(o:ClassA, o2:ClassA)
The bench result is getting even worse when the initial collection is bigger.
I would like to know what my mistake is.
Thanks for sharing your knowledge!
Best regards
Just a note on asynchronous processing / parallelism ... in general when processing stuff in parallel you end up with quite a lot of CPU-bound overhead for synchronizing the results.
The overhead can in fact be so significant that it can nullify the time gains that you get from multiple CPU cores working in parallel.
You should also get familiar with Amdahl's Law. Take a look at those numbers: with a parallel portion of 75% you reach the maximum speedup possible with only 4 processors. And with a parallel portion of 50%, you reach the maximum speedup with only 2 processors.
And this is only the theoretical limit, because you also have the shared-memory synchronization between processors which can get really messy; basically processors are optimized for sequential execution. Introduce concurrency concerns and you need to force ordering with memory barriers, which nullify many CPU optimizations. And thus you can reach a negative speedup, as seen in your tests actually.
So you're testing asynchronous / parallel mapping, but the test is basically doing nothing at all, might as well test with the identity function and it would be almost the same thing. In other words the test that you're doing and its results are pretty much useless in practice.
And as a side-note, this is also why I never liked the idea of "parallel collections". The concept is flawed, because you can only use parallel collections for purely CPU-bound stuff (i.e. no I/O, no actual async stuff), which lets say that it is fine for doing some calculations, except that:
for many purposes usage of parallel collections is slower than the normal operators that use a single CPU and
if you actually have CPU-bound work and you need to use your hardware resources to the max, then "parallel collections" in their current incarnation are actually the wrong abstraction, because "hardware" these days includes GPUs
In other words parallel collections are not using hardware resources efficiently, since they totally ignore GPU support and are totally inadequate for mixed CPU - I/O tasks, since they lack asynchrony support.
I feel the need to mention this because too often people think that rubbing some "parallel" pixie dust on their code will make it run faster, but many times it won't.
Parallelism works great when you've got I/O-bound tasks (mixed with CPU-bound tasks of course) and in that case the CPU overhead is much less significant, because processing time is going to be dominated by I/O.
PS: plain mapping over Scala collections should be faster because it is strict and (depending on the collection type) it uses array-backed buffers and thus don't trash CPU caches. Monix's .map has the same overhead as Scala's Iterable.map, or in other words near-zero overhead, but its application is lazy and introduces some boxing overhead, which we can't get rid of because the JVM doesn't specialize generics.
It's damn fast in practice though ;-)
I've updated the code and the bench is really better than before. The difference is related to the List operator. In fact, the first version was using append instead of preprend. Since List is a linked list, it had to iterate over the elements in order to add a new one. By being lazy, I wanted to use _ operator but I should have not.
package benches
import java.util.concurrent.TimeUnit
import akka.NotUsed
import akka.actor.ActorSystem
import akka.stream.{ActorMaterializer, ClosedShape, UniformFanInShape, UniformFanOutShape}
import akka.stream.scaladsl.{Balance, Flow, GraphDSL, Keep, Merge, RunnableGraph, Sink, Source}
import org.openjdk.jmh.annotations._
import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
import scala.collection.immutable.Seq
#OutputTimeUnit(TimeUnit.MILLISECONDS)
#BenchmarkMode(Array(Mode.SingleShotTime))
#Warmup(iterations = 20)
#Measurement(iterations = 20)
#Fork(value = 1, jvmArgs = Array("-server", "-Xmx8g"))
#Threads(1)
class MappingBenchmark {
import monix.eval._
import monix.reactive._
import monix.execution.Scheduler.Implicits.global
def list: Seq[ClassA] = (1 to 10000).map(ClassA).toList
// val l = (1 to 135368).map(Offre).toList
// ##### SCALA ##### //
def foldClassB = (l:List[ClassB], o:ClassB) => o +: l
#Benchmark
def map: Seq[ClassB] = list.map(o => ClassB(o, o))
#Benchmark
def parMap: Seq[ClassB] = list.par.map(o => ClassB(o, o)).toList
// ##### MONIX ##### //
#Benchmark
def monixTaskGather: Seq[ClassB] = {
val task: Task[Seq[ClassB]] = Task.gatherUnordered(list.map(o => Task(ClassB(o,o))))
Await.result(task.runAsync, Duration.Inf)
}
#Benchmark
def monixBatchedObservables: Seq[ClassB] = {
val task: Task[Seq[ClassB]] =
Observable.fromIterable(list)
.bufferIntrospective(256)
.flatMap{items =>
val tasks = items.map(o => Task(ClassB(o,o)))
val batches = tasks.sliding(10,10).map(b => Task.gatherUnordered(b))
val aggregate: Task[Iterator[ClassB]] = Task.sequence(batches).map(_.flatten)
Observable.fromTask(aggregate).flatMap(i => Observable.fromIterator(i))
}.consumeWith(Consumer.foldLeft(List[ClassB]())(foldClassB))
Await.result(task.runAsync, Duration.Inf)
}
#Benchmark
def monixMapFoldLeft: Seq[ClassB] = {
val task: Task[Seq[ClassB]] = Observable.fromIterable(list).map(o => ClassB(o, o)).consumeWith(Consumer.foldLeft(List[ClassB]())(foldClassB))
Await.result(task.runAsync, Duration.Inf)
}
#Benchmark
def monixMapFoldLeftAsync: Seq[ClassB] = {
val task: Task[Seq[ClassB]] = Observable.fromIterable(list).map(o => ClassB(o, o)).consumeWith(Consumer.foldLeftAsync(List[ClassB]())((l, o) => Task(o +: l)))
Await.result(task.runAsync, Duration.Inf)
}
#Benchmark
def monixMapAsyncFoldLeft: Seq[ClassB] = {
val task: Task[Seq[ClassB]] = Observable.fromIterable(list).mapAsync(4)(o => Task(ClassB(o, o))).consumeWith(Consumer.foldLeft(List[ClassB]())(foldClassB))
Await.result(task.runAsync, Duration.Inf)
}
#Benchmark
def monixMapAsyncFoldLeftAsync: Seq[ClassB] = {
val task: Task[Seq[ClassB]] = Observable.fromIterable(list).mapAsync(4)(o => Task(ClassB(o, o))).consumeWith(Consumer.foldLeftAsync(List[ClassB]())((l, o) => Task(o +: l)))
Await.result(task.runAsync, Duration.Inf)
}
// ##### AKKA-STREAM ##### //
#Benchmark
def akkaMapFold: Seq[ClassB] = {
val graph: RunnableGraph[Future[List[ClassB]]] = Source(list).map(o => ClassB(o,o)).toMat(Sink.fold(List[ClassB]())(foldClassB))(Keep.right)
runAkkaGraph(graph)
}
#Benchmark
def akkaMapFoldAsync: Seq[ClassB] = {
val graph: RunnableGraph[Future[List[ClassB]]] = Source(list).map(o => ClassB(o,o)).toMat(Sink.foldAsync(List[ClassB]())((l, o) => Future(o +: l)))(Keep.right)
runAkkaGraph(graph)
}
#Benchmark
def akkaMapSeq: Seq[ClassB] = {
val graph = Source(list).map(o => ClassB(o,o)).toMat(Sink.seq)(Keep.right)
runAkkaGraph(graph)
}
#Benchmark
def akkaMapAsyncFold: Seq[ClassB] = {
def graph: RunnableGraph[Future[Seq[ClassB]]] = Source(list).mapAsync(4)(o => Future(ClassB(o,o))).async.toMat(Sink.fold(List[ClassB]())(foldClassB))(Keep.right)
runAkkaGraph(graph)
}
#Benchmark
def akkaMapAsyncFoldAsync: Seq[ClassB] = {
def graph: RunnableGraph[Future[Seq[ClassB]]] = Source(list).mapAsync(4)(o => Future(ClassB(o,o))).async.toMat(Sink.foldAsync(List[ClassB]())((l, o) => Future(o +: l)))(Keep.right)
runAkkaGraph(graph)
}
#Benchmark
def akkaMapAsyncSeq: Seq[ClassB] = {
val graph = Source(list).mapAsync(4)(o => Future(ClassB(o,o))).toMat(Sink.seq)(Keep.right)
runAkkaGraph(graph)
}
#Benchmark
def akkaLoadBalanceMap: Seq[ClassB] = {
def graph: RunnableGraph[Future[Seq[ClassB]]] = {
val sink: Sink[ClassB, Future[Seq[ClassB]]] = Sink.fold(List[ClassB]())(foldClassB)
RunnableGraph.fromGraph[Future[Seq[ClassB]]](GraphDSL.create(sink) { implicit builder =>
sink =>
import GraphDSL.Implicits._
val balance: UniformFanOutShape[ClassA, ClassA] = builder.add(Balance[ClassA](4))
val merge: UniformFanInShape[ClassB, ClassB] = builder.add(Merge[ClassB](4))
val mapClassB: Flow[ClassA, ClassB, NotUsed] = Flow[ClassA].map(o => ClassB(o,o))
Source(list) ~> balance
(1 to 4).foreach{ i =>
balance ~> mapClassB.async ~> merge
}
merge ~> sink
ClosedShape
})
}
runAkkaGraph(graph)
}
#Benchmark
def akkaLoadBalanceMapSeq: Seq[ClassB] = {
def graph: RunnableGraph[Future[Seq[ClassB]]] = {
val sink: Sink[ClassB, Future[Seq[ClassB]]] = Sink.seq
RunnableGraph.fromGraph[Future[Seq[ClassB]]](GraphDSL.create(sink) { implicit builder =>
sink =>
import GraphDSL.Implicits._
val balance: UniformFanOutShape[ClassA, ClassA] = builder.add(Balance[ClassA](4))
val merge: UniformFanInShape[ClassB, ClassB] = builder.add(Merge[ClassB](4))
val mapClassB: Flow[ClassA, ClassB, NotUsed] = Flow[ClassA].map(o => ClassB(o,o))
Source(list) ~> balance
(1 to 4).foreach{ i =>
balance ~> mapClassB.async ~> merge
}
merge ~> sink
ClosedShape
})
}
runAkkaGraph(graph)
}
private def runAkkaGraph(g:RunnableGraph[Future[Seq[ClassB]]]): Seq[ClassB] = {
implicit val actorSystem = ActorSystem("app")
implicit val actorMaterializer = ActorMaterializer()
val eventualBs = g.run()
val res = Await.result(eventualBs, Duration.Inf)
actorSystem.terminate()
res
}
}
case class ClassA(a:Int)
case class ClassB(o:ClassA, o2:ClassA)
The result with this updated class is :
[info] Benchmark Mode Cnt Score Error Units
[info] MappingBenchmark.akkaLoadBalanceMap ss 20 19,052 â–’ 3,779 ms/op
[info] MappingBenchmark.akkaLoadBalanceMapSeq ss 20 16,115 â–’ 3,232 ms/op
[info] MappingBenchmark.akkaMapAsyncFold ss 20 20,862 â–’ 3,127 ms/op
[info] MappingBenchmark.akkaMapAsyncFoldAsync ss 20 26,994 â–’ 4,010 ms/op
[info] MappingBenchmark.akkaMapAsyncSeq ss 20 19,399 â–’ 7,089 ms/op
[info] MappingBenchmark.akkaMapFold ss 20 12,132 â–’ 4,111 ms/op
[info] MappingBenchmark.akkaMapFoldAsync ss 20 22,652 â–’ 3,802 ms/op
[info] MappingBenchmark.akkaMapSeq ss 20 10,894 â–’ 3,114 ms/op
[info] MappingBenchmark.map ss 20 0,625 â–’ 0,193 ms/op
[info] MappingBenchmark.monixBatchedObservables ss 20 9,175 â–’ 4,080 ms/op
[info] MappingBenchmark.monixMapAsyncFoldLeft ss 20 11,724 â–’ 4,458 ms/op
[info] MappingBenchmark.monixMapAsyncFoldLeftAsync ss 20 14,174 â–’ 6,962 ms/op
[info] MappingBenchmark.monixMapFoldLeft ss 20 1,057 â–’ 0,960 ms/op
[info] MappingBenchmark.monixMapFoldLeftAsync ss 20 9,638 â–’ 4,910 ms/op
[info] MappingBenchmark.monixTaskGather ss 20 7,065 â–’ 2,428 ms/op
[info] MappingBenchmark.parMap ss 20 1,392 â–’ 0,923 ms/op
it seems that it is still faster to map with scala if we can before running a stream.

Non-Terminating ZeroMQ Load Balancer

Given the following slightly modified Load Balancer ZeroMQ code:
package net.broker
import org.zeromq.ZMQ
object LruQueue2 {
class ClientTask(name: String) extends Runnable {
override def run(): Unit = {
val context = ZMQ.context(1)
val client = context.socket(ZMQ.REQ)
client.setIdentity(name.getBytes)
client.connect("tcp://localhost:5555")
// send request, get reply
client.send("HELLO".getBytes, 0)
val reply = client.recv(0)
println(s"${new String(client.getIdentity)} received: ${new String(reply)}")
}
}
class WorkerTask(name: String) extends Runnable {
override def run(): Unit = {
val context = ZMQ.context(1)
val worker = context.socket(ZMQ.REQ)
worker.connect("tcp://localhost:5556")
worker.setIdentity(name.getBytes)
worker.send("READY".getBytes, 0)
while(true) {
val clientAddr = worker.recv(0)
val empty = worker.recv(0)
val clientMsg = worker.recv(0)
worker.send(clientAddr, ZMQ.SNDMORE)
worker.send("".getBytes, ZMQ.SNDMORE)
worker.send("WORLD".getBytes, 0)
println(s"${new String(worker.getIdentity)}: 3-frames to client: ${new String(clientAddr)}")
}
}
}
def main(args: Array[String]): Unit = {
val NOFLAGS = 0
// worker using REQ socket to do LRU routing
val NBR_CLIENTS = 1
val NBR_WORKERS = 1
val context = ZMQ.context(1)
val frontend = context.socket(ZMQ.ROUTER)
val backend = context.socket(ZMQ.ROUTER)
frontend.bind("tcp://*:5555")
backend.bind("tcp://*:5556")
val clients = (1 to NBR_CLIENTS).toList.map{ i => new Thread(new ClientTask(s"CLIENT$i"))}
val workers = (1 to NBR_CLIENTS).toList.map{ i => new Thread(new WorkerTask(s"WORKER$i"))}
clients.foreach(_.start)
workers.foreach(_.start)
val workerQueue = scala.collection.mutable.Queue[Array[Byte]]()
val poller = context.poller(2)
poller.register(backend, ZMQ.Poller.POLLIN)
poller.register(frontend, ZMQ.Poller.POLLIN)
var clientNbr = NBR_CLIENTS
while(true) {
println("begin to poll")
poller.poll()
println("done polling")
println("clientNbr:" + clientNbr)
println("workerQueue.length: " + workerQueue.length)
if(clientNbr == 0) {
sys.exit(0)
}
else if(poller.pollin(0) && clientNbr > 0) {
val workerAddr = backend.recv(NOFLAGS)
val empty = backend.recv(NOFLAGS)
val clientAddrOrReadyMsg = backend.recv(NOFLAGS)
workerQueue.enqueue(workerAddr)
if(new String(clientAddrOrReadyMsg) == "READY") {
// nothing to do - worker is letting us know that he's ready to work
}
else {
// retrieve remaining 2 frames of client message
// [Empty][Client Message of "HELLO"]
val empty = backend.recv(0)
val workerResponse = backend.recv(0)
frontend.send(clientAddrOrReadyMsg, ZMQ.SNDMORE)
frontend.send("".getBytes, ZMQ.SNDMORE)
frontend.send(workerResponse, NOFLAGS)
clientNbr -= 1
}
}
else if (poller.pollin(1) && workerQueue.nonEmpty) {
val clientAddr = frontend.recv(0)
val empty = frontend.recv(0)
val clientMsg = frontend.recv(0)
backend.send(workerQueue.dequeue(), ZMQ.SNDMORE)
backend.send("".getBytes, ZMQ.SNDMORE)
backend.send(clientAddr, ZMQ.SNDMORE)
backend.send("".getBytes, ZMQ.SNDMORE)
backend.send(clientMsg, NOFLAGS)
}
else {}
}
}
}
When I run the above code, I see the following output:
[info] Running net.broker.LruQueue2
[info] begin to poll
[info] done polling
[info] clientNbr:1
[info] workerQueue.length: 0
[info] begin to poll
[info] done polling
[info] clientNbr:1
[info] workerQueue.length: 1
[info] begin to poll
[info] WORKER1: 3-frames to client: CLIENT1
[info] done polling
[info] clientNbr:1
[info] workerQueue.length: 0
[info] begin to poll
[info] CLIENT1 received: WORLD
It appears that it's stuck on poller.poll(), per the output print statements.
How can I debug this behavior?

ThreadPoolExecution error with scala, slick, specs2

I am trying to write a db unit test for my module using slick and specs2 in scala language. I have written two tests at the moment but the second one fails with ThreadPoolExecution error.
I have tried many approaches but still can't manage to solve my problem.
Any help would be greatly appreciated.
Here is the test code:
class UserClientSpecs extends Specification{
"App should " should {
"add value to database" in new WithApplication {
println("before first test")
val recordEntry = new UserClient(None, "Lohs_atkal", 2)
val newRecord = UserService.addUser(recordEntry)
newRecord.onComplete {
case Success(value) => println(s"Got the callback, meaning = $value")
case Failure(e) => println(e.getMessage)
}
newRecord should not beNull
val count = UserService.listAllUsers.map {
v =>
println("the number of database entries are " + v.length)
}
}
"delete a record" in new WithApplication {
println("before second test")
val recordEntry = new UserClient(Some(0), "Lielaks Lohs", 5)
val newRecord = UserService.addUser(recordEntry)
newRecord.map {
v => println("newRecord value", v)
}
newRecord.onComplete {
case Success(value) => println(s"Got the callback, meaning = $value")
case Failure(e) => println(e.getMessage)
}
val recordEntry2 = new UserClient(Some(1), "Lielaks Lohs2", 50)
val newRecord2 = UserService.addUser(recordEntry2)
val countOne = UserService.listAllUsers.map {
res =>
println(res.length)
}
val deleteUser = UserService.deleteUser(1)
val countTwo = UserService.listAllUsers.map {
res =>
res should_==(1)
res should !==(2)
}
}
}
}
And the error I am getting when running my test through sbt -> testOnly:
[play-scala] $ testOnly models.UserClientSpecs
[info] UserClientSpecs
[info]
before first test
Got the callback, meaning = Some(UserClient(None,Lohs_atkal,2))
the number of database entries are 1
[info] App should should
[info] + add value to database
before second test
Task slick.backend.DatabaseComponent$DatabaseDef$$anon$2#6d01394 rejected from java.util.concurrent.ThreadPoolExecutor#7fa5be9b[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 2]
[info] + delete a record
[info]
[info] Total for specification UserClientSpecs
[info] Finished in 2 seconds, 739 ms
[info] 2 examples, 0 failure, 0 error
[info]
[info] Passed: Total 2, Failed 0, Errors 0, Passed 2
[success] Total time: 8 s, completed Mar 10, 2016 1:40:10 PM

Writing ScalaTest for ReactiveMongoApi in Playframework 2.4?

I am trying to start writing test for mongodb in my play application.
It seems that I can not get it working because the connection is shutdown before the save is executed.
Here are the results
[info] UserDaoMongoSpec:
[info] UserDao
[info] - application - ReactiveMongoApi starting...
[info] - application - ReactiveMongoApi successfully started with DB 'test'! Servers:
[localhost:27017]
[info] - should save users and find them by userId
[info] - application - ReactiveMongoApi stopping...
[info] - application - ReactiveMongoApi connections stopped. [Success(Closed)]
[INFO] [12/24/2015 15:36:43.961] [reactivemongo-akka.actor.default-dispatcher-4] [akka://reactivemongo/user/Monitor-3] Message [reactivemongo.core.actors.Close$] from Actor[akka://reactivemongo/deadLetters] to Actor[akka://reactivemongo/user/Monitor-3#1192398481] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
[info] ScalaTest
[info] Run completed in 3 seconds, 989 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[info] Passed: Total 1, Failed 0, Errors 0, Passed 1
This is the code of the test, which is not testing anything, but I am trying first to write the database.
package test.daos
import scala.concurrent.ExecutionContext.Implicits.global
import daos.impl.UserDaoMongo
import org.scalatest._
import play.api.test._
import play.api.test.Helpers._
import org.scalatestplus.play._
class UserDaoMongoSpec extends DaosApplicationSpecOneAppPerTest {
"UserDao" should {
"save users and find them by userId" in {
val userDao = new UserDaoMongo
val future = for {
_ <- userDao.save(credentialsTestUser)
maybeUser <- userDao.find(credentialsTestUser.id)
} yield maybeUser.map(_ == credentialsTestUser)
}
}
}
And the dao implementation
package daos.impl
import java.util.UUID
import scala.concurrent.Future
import play.api.Play.current
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import play.api.libs.json.Json
import play.modules.reactivemongo.ReactiveMongoApi
import play.modules.reactivemongo.json._
import play.modules.reactivemongo.json.collection.JSONCollection
import com.mohiva.play.silhouette.api.LoginInfo
import models.{User, Profile}
import models.User._
import daos.api.UserDao
import play.api.Logger
class UserDaoMongo extends UserDao {
lazy val reactiveMongoApi = current.injector.instanceOf[ReactiveMongoApi]
val users = reactiveMongoApi.db.collection[JSONCollection]("users")
def find(loginInfo:LoginInfo):Future[Option[User]] =
users.find(Json.obj("profiles.loginInfo" -> loginInfo)).one[User]
def find(userId:UUID):Future[Option[User]] ={
Logger.debug("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
users.find(Json.obj("id" -> userId)).one[User]
}
def save(user:User):Future[User] =
users.insert(user).map(_ => user)
def confirm(loginInfo:LoginInfo):Future[User] = for {
_ <- users.update(Json.obj(
"profiles.loginInfo" -> loginInfo
), Json.obj("$set" -> Json.obj("profiles.$.confirmed" -> true)))
user <- find(loginInfo)
} yield user.get
def link(user:User, profile:Profile) = for {
_ <- users.update(Json.obj(
"id" -> user.id
), Json.obj("$push" -> Json.obj("profiles" -> profile)))
user <- find(user.id)
} yield user.get
def update(profile:Profile) = for {
_ <- users.update(Json.obj(
"profiles.loginInfo" -> profile.loginInfo
), Json.obj("$set" -> Json.obj("profiles.$" -> profile)))
user <- find(profile.loginInfo)
} yield user.get
}
What could be that I am doing wrong?
Thank you
As says in the comments, it turns out that the mistake was that I was not waiting for the future completion. I decided to use ScalaTest specific function to make tests wait for the futures completions
Here is the code
"UserDao" should {
"save users and find them by userId" in withUserDao { userDao =>
val future = for {
user <- userDao.save(credentialsTestUser)
maybeUser <- userDao.find(credentialsTestUser.id)
} yield {
maybeUser.map(_ == credentialsTestUser)
}
whenReady (future) { result =>
result.get must be (true)
}
}
}
and just in case, I override the default behaviour because the default time was not enough
implicit override val patienceConfig =
PatienceConfig(timeout = Span(2, Seconds), interval = Span(5, Millis))
Thank you

File writing iteratee does not receive EOF for WS.get

I have created a simple iteratee to download a file using WS as explained in this link.
Consider the following snippet:
import java.nio.ByteBuffer
import java.nio.channels.FileChannel
import org.specs2.mutable.Specification
import org.specs2.time.NoTimeConversions
import play.api.libs.Files.TemporaryFile
import play.api.libs.iteratee.{Done, Input, Cont, Iteratee}
import play.api.libs.ws.WS
import scala.concurrent.Await
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
class DummySpec extends Specification with NoTimeConversions {
def fileChannelIteratee(channel: FileChannel): Iteratee[Array[Byte], Unit] = Cont {
case Input.EOF =>
println("Input.EOF")
channel.close()
Done(Unit, Input.EOF)
case Input.El(bytes) =>
println("Input.El")
val buf = ByteBuffer.wrap(bytes)
channel.write(buf)
fileChannelIteratee(channel)
case Input.Empty =>
println("Input.Empty")
fileChannelIteratee(channel)
}
"fileChannelIteratee" should {
"work" in {
val file = TemporaryFile.apply("test").file
val channel = FileChannel.open(file.toPath)
val future = WS.url("http://www.example.com").get(_ => fileChannelIteratee(channel)).map(_.run)
Await.result(future, 10.seconds)
file.length !== 0
}
}
}
Calling .map(_.run) after WS.get seems to have no effect here as the iteratee does not seem to receive Input.EOF. It prevents me from being able to close the channel. This is the output I get:
Input.El
[info] DummySpec
[info]
[info] fileChannelIteratee should
[info] x work (941 ms)
[error] '0' is equal to '0' (DummySpec.scala:37)
[info]
[info]
[info] Total for specification DummySpec
[info] Finished in 948 ms
[info] 1 example, 1 failure, 0 error
What am I doing wrong?
I am using Play Framework 2.2.2.
Thanks in advance.
I was opening the FileChannel in a wrong way. It seems to default to read mode according to this link when no parameters are given.
The exception thrown from channel.write was being swallowed by map operation as the return type of the whole operation is Future[Future[Unit]]. The outer Future is in a successful state even if the internal one fails in this case. flatMap should be used instead.