为什么Akka Streams吞噬了我的异常?

时间:2016-02-25 15:38:34

标签: scala exception-handling akka-stream

为什么

中有例外
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.Source

object TestExceptionHandling {
  def main(args: Array[String]): Unit = {
    implicit val actorSystem = ActorSystem()
    implicit val materializer = ActorMaterializer()(defaultActorSystem)

    Source(List(1, 2, 3)).map { i =>
      if (i == 2) {
        throw new RuntimeException("Please, don't swallow me!")
      } else {
        i
      }
    }.runForeach { i =>
      println(s"Received $i")
    }
  }
}

默默无视?我可以看到在打印Received 1后流停止,但没有记录任何内容。请注意,问题通常不是日志记录配置,因为如果我在akka.log-config-on-start = on文件中设置application.conf,我会看到很多输出。

2 个答案:

答案 0 :(得分:15)

我现在正在使用自定义<script> google.setOnLoadCallback(drawChart); function drawChart() { var data = google.visualization.arrayToDataTable([ ['Month', 'Movie'], ['1', <?php echo $Total[0]; ?>], ['2', <?php echo $Total[1]; ?>], ['3', <?php echo $Total[2]; ?>], ['4', <?php echo $Total[3]; ?>], ['5', <?php echo $Total[4]; ?>], ['6', <?php echo $Total[5]; ?>], ['7', <?php echo $Total[6]; ?>], ['8', <?php echo $Total[7]; ?>], ['9', <?php echo $Total[8]; ?>], ['10', <?php echo $Total[9]; ?>], ['11', <?php echo $Total[10]; ?>], ['12', <?php echo $Total[11]; ?>], ['13', <?php echo $Total[12]; ?>], ['14', <?php echo $Total[13]; ?>], ['15', <?php echo $Total[14]; ?>], ['16', <?php echo $Total[15]; ?>], ['17', <?php echo $Total[16]; ?>], ['18', <?php echo $Total[17]; ?>], ['19', <?php echo $Total[18]; ?>], ['20', <?php echo $Total[19]; ?>], ['21', <?php echo $Total[20]; ?>], ['22', <?php echo $Total[21]; ?>], ['23', <?php echo $Total[22]; ?>], ['24', <?php echo $Total[23]; ?>], ['25', <?php echo $Total[24]; ?>] ]); ... etc... </script> 来确保正确记录异常,可以这样设置:

Supervision.Decider

另外,正如Vikor Klang所指出的那样,在上面给出的例子中,异常也可以通过

“抓住”
val decider: Supervision.Decider = { e =>
  logger.error("Unhandled exception in stream", e)
  Supervision.Stop
}

implicit val actorSystem = ActorSystem()
val materializerSettings = ActorMaterializerSettings(actorSystem).withSupervisionStrategy(decider)
implicit val materializer = ActorMaterializer(materializerSettings)(actorSystem)

但请注意,此方法无法帮助您

Source(List(1, 2, 3)).map { i =>
  if (i == 2) {
    throw new RuntimeException("Please, don't swallow me!")
  } else {
    i
  }
}.runForeach { i =>
  println(s"Received $i")
}.onComplete {
  case Success(_) =>
    println("Done")
  case Failure(e) =>
    println(s"Failed with $e")
}

因为Source(List(1, 2, 3)).map { i => if (i == 2) { throw new RuntimeException("Please, don't swallow me!") } else { i } }.to(Sink.foreach { i => println(s"Received $i") }).run() 返回run()

答案 1 :(得分:5)

当我开始使用akk-streams时,我有类似的问题。 Supervision.Decider帮助但并非总是如此。

不幸的是,它并没有捕获ActionPublisher中引发的异常。我看到它被处理了,ActorPublisher.onError被调用但它没有到达Supervision.Decider。它适用于文档中提供的简单Stream。

如果我使用Sink.actorRef,错误也无法触及演员。

为了实验,我尝试了以下示例

val stream = Source(0 to 5).map(100 / _)
stream.runWith(Sink.actorSubscriber(props))

在这种情况下,Decider捕获了异常,但从未到达actor订阅者。

总的来说,我认为这是一种不一致的行为。我不能使用一种机制来处理Stream中的错误。

我原来的问题:Custom Supervision.Decider doesn't catch exception produced by ActorPublisher

以下是跟踪的问题:https://github.com/akka/akka/issues/18359