使用Akka actor时正确的异常处理方式

时间:2019-01-17 04:11:16

标签: scala akka

我正在尝试使用主管在Akka项目中进行适当的异常处理。只是想确定这是否是正确的处理方式。 我有1个Actor系统,它创建了4个独立的actor。让我说有1个actor命中了DB。监督策略是处理事情的正确方法吗?

object ExceptionHandlingSupervisor extends App{
  val actorSystem = ActorSystem("ExceptionHandlingActorSystem")
  val actor = actorSystem.actorOf(Props[SupervisorActor], "SupervisorActor")
  actor ! Start

  class SupervisorActor extends Actor {
    val dbActor = context.actorOf(Props[ChildActor],"ChildActor")
    override def receive: Receive = {
      case Start => dbActor ! HitDatabase("","")
    }

    override val supervisorStrategy = OneForOneStrategy(loggingEnabled = false){
      case ae:SQLException => println("Found an SQLException") //Add my logging logic here and error notification logic here
        Resume

      case _:Exception => println("Found an Exception")
        Restart

    }

  }

  class ChildActor extends Actor{
    override def receive: Receive = {
      case HitDatabase(user,pass) => dbFunction(user,pass)
    }
  }
}

上面的代码是采用这种方法的方法,还是我应该坚持使用传统的Try / Catch块:

class DbActor extends Actor{
        override def receive: Receive = {
          case HitDatabase(user,pass) => 
    try{
            dbFunction(user,pass)
          }
            catch {
              case ae:SQLException => println("Found an SQLException") //Add my logging logic here and error notification logic here
            }

如果您能告诉我,我也将不胜感激, 在这种情况下,为什么会选择监督方法而不是常规的异常处理? 除了执行Resume或Restart之外,我们是否可以在supervisorStrategy中指定其他错误处理逻辑?

1 个答案:

答案 0 :(得分:2)

除非有必要以非常精细的方式或在各个参与者之间以不同的方式处理异常,否则我将让内置的supervisorStrategy处理异常以及相应的参与者重新启动/终止等。这样做还具有更好的好处。通过在故障处理逻辑中占据中心位置来提高可读性。

  

我们可以在超级用户策略中指定其他错误处理逻辑吗?   除了仅执行“继续”还是“重新启动”之外?

supervisorStrategy中还有其他故障处理操作,例如Stop, EscalateStop终止子级演员,Escalate向上级扩展至主管的父级。只要decider代码块符合Directive,就可以在返回每个case中的PartialFunction[Throwable, Directive]之前添加自定义代码。例如:

override val supervisorStrategy =
  OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
    case e: ArithmeticException =>
      myLogActor ! s"ERROR: $e from $sender; Resuming."
      Resume
    case _: Exception =>
      myLogActor ! s"ERROR: unknown exception from $sender; Escalating."
      Escalate
  }

请注意,如果必须采用try/catch方法,请考虑改用Try,如下所示:

Try(dbFunction(user, pass)) match {
  case Success(res)             => // do something with `res`
  case Failure(e: SQLException) => // log `e`, etc
  case Failure(e)               => // other exceptions ...
}