最近我问的是以下问题的发展: How do I dynamically add Source to existing Graph?
假设您有元素Source[T, NotUsed]
的源队列。您通过.offer()
调用放置了子流。使用flatMapConcat
?
我尝试将Promise[T]
放在子流的末尾,但没有保证在它之前的元素不会被处理得更慢。这是演示问题的代码
trait PipeElement
case class Link(url: String) extends PipeElement
case class Ids(ids: List[Int]) extends PipeElement
case class Title(text: String) extends PipeElement
case class Completion(p: Promise[Unit]) extends PipeElement
val (queue, completionFut) = Source
.queue[Source[PipeElement, NotUsed]](10, backpressure)
.flatMapConcat(identity)
.buffer(2, OverflowStrategy.backpressure)
.mapAsync(4) {
case Link(url) => Future{
Thread.sleep(500)
Some("url: " + url)
}
case Ids(ids) => Future{
Some("ids: " + ids)
}
case Title(title) => Future{
Some("title: " + title)
}
case Completion(p) =>
p.success(Unit)
Future.successful(Some("Promise delivered"))
}
.toMat(Sink.foreach(println))(Keep.both)
.run()
val promise = Promise[Unit]()
val lst = List(Link("Link"), Ids(List(1,2,3)), Title("title"), Completion(promise))
queue.offer(Source(lst))
queue.offer(Source(List(Link("Link2"), Link("Link3"))))
queue.complete()
promise.future.onComplete {
case Success(res) =>
println("promise: " + res)
// system.terminate()
case Failure(ex) =>
ex.printStackTrace()
system.terminate()
}
completionFut.onComplete {
case Success(res) =>
println("Stream is finished: " + res)
system.terminate()
case Failure(ex) =>
ex.printStackTrace()
system.terminate()
}
Await.result(system.whenTerminated, Duration.Inf)
输出
promise: ()
Some(url: Link)
Some(ids: List(1, 2, 3))
Some(title: title)
Some(Promise delivered)
Some(url: Link2)
Some(url: Link3)
Stream is finished: Done
我可以通过从Either[Promise[Unit], String]
返回mapAsync
然后过滤/收集此类元素来解决此问题
.collect {
case Left(p) if {
p.success(Unit)
false
} => ???
case Right(v) => v
}
它有效,但对我来说看起来太黑了:))
想法?