使用失败溢出策略时Akka stream Source.queue挂起

使用失败溢出策略时Akka stream Source.queue挂起,akka,akka-stream,Akka,Akka Stream,以下Scala代码段似乎没有返回: val队列= Source.queue[Unit](10,OverflowStrategy.fail) .节流阀(1,1秒,1,节流模式成形) .to(下沉。忽略) .run() 等待结果( (1到15)。映射(=>queue.offer(())。最后, 持续时间(Inf) 这是阿克卡溪流中的一只虫子还是我做错了什么 编辑:只是循环一下,这个bug是在Akka打开并被接受的:这个程序让我们更深入地了解这里发生了什么: import akka.actor.Ac

以下Scala代码段似乎没有返回:

val队列=
Source.queue[Unit](10,OverflowStrategy.fail)
.节流阀(1,1秒,1,节流模式成形)
.to(下沉。忽略)
.run()
等待结果(
(1到15)。映射(=>queue.offer(())。最后,
持续时间(Inf)
这是阿克卡溪流中的一只虫子还是我做错了什么


编辑:只是循环一下,这个bug是在Akka打开并被接受的:

这个程序让我们更深入地了解这里发生了什么:

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()之前,您始终需要等待提交的最后一个将来完成

但是,阿克卡挂起期货不是一个错误吗?这不应该让他们失望吗?这是可能的。我也觉得这有点令人惊讶;
queue.offer
的契约明确指出,如果在不适当的时间调用
offer
,它将在将来失败,但出于某种原因,它没有在这里调用。也许值得为此创建一个bug报告。