Akka流 - 失败后用广播和zip恢复图形

时间:2017-10-31 09:51:59

标签: scala stream akka akka-stream

我有一个内置广播和zip的流程图。如果某个东西(无论它是什么)在这个流程中失败了,我想删除传递给它的有问题的元素并恢复。我提出了以下解决方案:

val flow = Flow.fromGraph(GraphDSL.create() { implicit builder =>
  import GraphDSL.Implicits._

  val dangerousFlow = Flow[Int].map {
    case 5 => throw new RuntimeException("BOOM!")
    case x => x
  }
  val safeFlow = Flow[Int]
  val bcast = builder.add(Broadcast[Int](2))
  val zip = builder.add(Zip[Int, Int])

  bcast ~> dangerousFlow ~> zip.in0
  bcast ~> safeFlow ~> zip.in1

  FlowShape(bcast.in, zip.out)
})

Source(1 to 9)
  .via(flow)
  .withAttributes(ActorAttributes.supervisionStrategy(Supervision.restartingDecider))
  .runWith(Sink.foreach(println))

我希望它能打印出来:

(1,1)
(2,2)
(3,3)
(4,4)
(5,5)
(6,6)
(7,7)
(8,8)
(9,9)

但是,它只会打印死锁:

(1,1)
(2,2)
(3,3)
(4,4)

我们已经完成了一些调试,结果是它将“恢复”策略应用于其子节点,这导致dangerousFlow在失败后恢复,从而要求bcast中的元素。在bcast需要另一个元素之前,safeFlow不会发出元素,这实际上从未发生过(因为它正在等待来自zip的需求)。

有没有办法恢复图表,无论其中一个阶段内出了什么问题?

1 个答案:

答案 0 :(得分:3)

我认为你很好地理解了这个问题。您看到,当您的元素5崩溃dangerousFlow时,您还应该停止正在经历5的元素safeFlow,因为如果它到达zip阶段,你有你描述的问题。我不知道如何在broadcastzip阶段之间解决您的问题,但是如何进一步推动问题,哪个更容易处理?

考虑使用以下dangerousFlow

import scala.util._
val dangerousFlow = Flow[Int].map {
  case 5 => Failure(new RuntimeException("BOOM!"))
  case x => Success(x)
}

即使出现问题,dangerousFlow仍会发出数据。然后,您可以像当前一样zip,只需添加collect阶段作为图表的最后一步。在流程中,这看起来像:

Flow[(Try[Int], Int)].collect {
  case (Success(s), i) => s -> i
}

现在,如果你真的希望输出(5, 5)元组,请使用以下内容:

Flow[(Try[Int], Int)].collect {
  case (Success(s), i) => s -> i
  case (_, i)          => i -> i
}