在Akka传播例外

时间:2017-09-14 21:54:52

标签: scala akka

我有一个简单的actor层次结构,如下所示:

root
  |
   -- parent1
  |   |
  |    -- child1_1
  |   |
  |    -- child1_2
  |
   -- parent2
      |
       -- child2_1
      |
       -- child2_2

root实现supervisorStrategy处理各种例外情况 如果在parent1parent2中发生未处理的异常,则会到达supervisorStrategy并正确处理。
如果在任何一个孩子中发生未处理的异常,那么我只是得到[ERROR] akka.actor.OneForOneStrategy并且就是这样。

如何在层次结构中获取任何未处理的错误以向上传播并到达处理它的root

我是否需要处理监督并在每个级别添加Escalate

1 个答案:

答案 0 :(得分:1)

如果异常的类型为Exception(或其子代),则默认监督策略是重新启动子actor。

如果没有为参与者定义超级用户策略,则默认情况下会处理以下异常:

  

ActorInitializationException将停止失败的子actor

     

ActorKilledException将停止失败的子actor

     

DeathPactException将停止失败的子actor

     

例外情况   重启失败的子actor

     

其他类型的Throwable将升级为父actor

所以是的,在这种情况下,您需要为每个级别添加监督策略。

示例:

import akka.actor.SupervisorStrategy.{Escalate, Restart, Resume, Stop}
import akka.actor.{Actor, ActorLogging, ActorSystem, OneForOneStrategy, Props}

import scala.concurrent.duration._

class RootActor extends Actor with ActorLogging {

  override val supervisorStrategy =
    OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
      case _: Exception                => {
        log.info("Got exception in root")
        Escalate
      }
    }

  override def receive: Receive = {
    case "START_ROOT" =>
      log.info("Started root actor")
      val parentActor = context.actorOf(Props(classOf[ParentActor]))
      parentActor ! "START_PARENT"
  }
}

class ParentActor extends Actor with ActorLogging {
  override val supervisorStrategy =
    OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
      case _: Exception                => {
        log.info("Got exception in parent")
        Escalate
      }
    }

  override def receive: Receive = {
    case "START_PARENT" =>
      log.info("Started parent actor")
      val childActor = context.actorOf(Props(classOf[ChildActor]))
      childActor ! "START_CHILD"
  }
}

class ChildActor extends Actor with ActorLogging {
  override def receive: Receive = {
    case "START_CHILD" =>
      throw new Exception("Exception from CHILD ACTOR")
      log.info("Started child actor")
  }

  override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
    log.info("Restarting child actor")
    super.preRestart(reason, message)
  }
}
object App {
  def main(args: Array[String]): Unit = {

    val system = ActorSystem("my-system")
    val rootActor = system.actorOf(Props(classOf[RootActor]))
    rootActor ! "START_ROOT"

  }
}

在这种情况下,来自子actor的异常将升级为root actor。