以下Scala代码段似乎没有返回:
val queue =
Source.queue[Unit](10, OverflowStrategy.fail)
.throttle(1, 1 second, 1, ThrottleMode.shaping)
.to(Sink.ignore)
.run()
Await.result(
(1 to 15).map(_ => queue.offer(())).last,
Duration.Inf)
这是Akka流中的错误还是我做错了什么?
编辑:回过头来看,这个错误在Akka中被打开并被接受:https://github.com/akka/akka/issues/23078
答案 0 :(得分:1)
该计划让您更深入地了解这里发生的事情:
import akka.actor.ActorSystem
import akka.stream.scaladsl.{Keep, Sink, Source}
import akka.stream.{ActorMaterializer, OverflowStrategy, ThrottleMode}
import scala.concurrent.Await
import scala.concurrent.duration._
object Test extends App {
implicit val actorSystem = ActorSystem()
implicit val materializer = ActorMaterializer()
import actorSystem.dispatcher
val (queue, finalFuture) =
Source.queue[Unit](10, OverflowStrategy.fail)
.map(_ => println("Before throttle"))
.throttle(1, 1.second, 1, ThrottleMode.shaping)
.map(_ => println("After throttle"))
.toMat(Sink.ignore)(Keep.both)
.run()
finalFuture.onComplete(r => println(s"Materialized future from ignore completed: $r"))
Await.result((1 to 25).map(_ => queue.offer(()).map(e => println(s"Offer result: $e"))).last, Duration.Inf)
}
它为我打印以下内容:
Offer result: Enqueued
After throttle
Before throttle
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Failure(akka.stream.BufferOverflowException: Buffer overflow (max capacity was: 10)!)
Materialized future from ignore completed: Failure(akka.stream.BufferOverflowException: Buffer overflow (max capacity was: 10)!)
但是有时会以异常结束:
Before throttle
After throttle
Before throttle
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Enqueued
Offer result: Failure(akka.stream.BufferOverflowException: Buffer overflow (max capacity was: 10)!)
Materialized future from ignore completed: Failure(akka.stream.BufferOverflowException: Buffer overflow (max capacity was: 10)!)
Exception in thread "main" java.lang.IllegalStateException: Stream is terminated. SourceQueue is detached
at akka.stream.impl.QueueSource$$anon$1$$anonfun$postStop$1.apply(Sources.scala:57)
at akka.stream.impl.QueueSource$$anon$1$$anonfun$postStop$1.apply(Sources.scala:56)
at akka.stream.stage.CallbackWrapper$$anonfun$invoke$1.apply$mcV$sp(GraphStage.scala:1373)
at akka.stream.stage.CallbackWrapper$class.akka$stream$stage$CallbackWrapper$$locked(GraphStage.scala:1379)
at akka.stream.stage.CallbackWrapper$class.invoke(GraphStage.scala:1369)
at akka.stream.impl.QueueSource$$anon$1.invoke(Sources.scala:47)
at akka.stream.impl.QueueSource$$anon$2.offer(Sources.scala:180)
at test.Test$$anonfun$4.apply(Test.scala:25)
at test.Test$$anonfun$4.apply(Test.scala:25)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
at scala.collection.immutable.Range.foreach(Range.scala:160)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
at test.Test$.delayedEndpoint$test$Test$1(Test.scala:25)
at test.Test$delayedInit$body.apply(Test.scala:10)
at scala.Function0$class.apply$mcV$sp(Function0.scala:34)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App$$anonfun$main$1.apply(App.scala:76)
at scala.App$$anonfun$main$1.apply(App.scala:76)
at scala.collection.immutable.List.foreach(List.scala:381)
at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35)
at scala.App$class.main(App.scala:76)
也就是说,你看到并发行动 - 你提交的期货是并行执行的,其中一个完成失败,但更常见的是他们只是挂起。如果你按照这样的顺序得到失败的未来,那么你会得到一个例外,否则你会得到一个无限的等待。
要确定您的流已实际终止,您必须直接查看它,就像上面所做的那样。但最重要的是,您最好不要将配置的事件数量推送到队列中,或者如果您确实希望这样做而使用OverflowStrategy.backpressure
,则始终需要等待您提交的最后一个未来在执行下一个offer()
之前完成。