我希望链接Flow
形式的一系列a -> Try[b]
,其中每个连续阶段处理前一个Success
的情况,并且最后的Sink
通常会处理所有Failure
。
这个或类似的东西可以简洁地编码吗?它实际上是一个线性流,但我不确定每个阶段的广播和合并有多短。
答案 0 :(得分:1)
解决此问题的一种方法是定义扇出阶段,将Try
分为2个流,具体取决于其结果
object PartitionTry {
def apply[T]() = GraphDSL.create[FanOutShape2[Try[T], Throwable, T]]() { implicit builder ⇒
import GraphDSL.Implicits._
val success = builder.add(Flow[Try[T]].collect { case Success(a) ⇒ a })
val failure = builder.add(Flow[Try[T]].collect { case Failure(t) ⇒ t })
val partition = builder.add(Partition[Try[T]](2, _.fold(_ ⇒ 0, _ ⇒ 1)))
partition ~> failure
partition ~> success
new FanOutShape2[Try[T], Throwable, T](partition.in, failure.out, success.out)
}
}
然后,您的通用流程可以提取Try
并将Failure
发送到选择的接收器,同时传递Success
es
object ErrorHandlingFlow {
def apply[T, MatErr](errorSink: Sink[Throwable, MatErr]): Flow[Try[T], T, MatErr] = Flow.fromGraph(
GraphDSL.create(errorSink) { implicit builder ⇒ sink ⇒
import GraphDSL.Implicits._
val partition = builder.add(PartitionTry[T]())
partition.out0 ~> sink
new FlowShape[Try[T], T](partition.in, partition.out1)
}
)
}
下面的用法示例
val source : Source[String, NotUsed] = Source(List("1", "2", "hello"))
val convert : Flow[String, Try[Int], NotUsed] = Flow.fromFunction((s: String) ⇒ Try{s.toInt})
val errorsSink : Sink[Throwable, Future[Done]] = Sink.foreach[Throwable](println)
val handleErrors: Flow[Try[Int], Int, Future[Done]] = ErrorHandlingFlow(errorsSink)
source.via(convert).via(handleErrors).runForeach(println)
请注意
Either
等。