如何处理问题模式和监督的异常

gra*_*Lle 9 scala akka akka-supervision

我该如何处理DbActor抛出的异常?我不确定如何处理它,应该管道故障情况?

class RestActor extends Actor with ActorLogging {
  import context.dispatcher

  val dbActor = context.actorOf(Props[DbActor])
  implicit val timeout = Timeout(10 seconds)


  override val supervisorStrategy: SupervisorStrategy = {
    OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 10 seconds) {
      case x: Exception => ???
    }
  }

  def receive = {
    case GetRequest(reqCtx, id) => {

        // perform db ask
       ask(dbActor, ReadCommand(reqCtx, id)).mapTo[SomeObject] onComplete {
        case Success(obj) => { // some stuff }
        case Failure(err) => err match {
          case x: Exception => ???
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

很高兴得到你的想法,提前谢谢!

cmb*_*ter 7

根据您的代码示例中的问题,我可以在此处看到几个问题:

  1. 当我在如何处理异常的定义中覆盖默认的超级用户行为时,我可以做什么类型的事情?

  2. 在使用时ask,当我得到我正在等待的Failure结果时,我可以做什么类型的事情Future

让我们先从第一个问题开始(通常是一个好主意).当您覆盖默认的主管策略时,您可以更改如何处理子actor中某些类型的未处理异常,以了解如何处理该失败的子actor.前一句中的关键词是unhandled.对于正在执行请求/响应的actor,您实际上可能希望处理(捕获)特定异常并返回某些响应类型(或者在上游未来失败,稍后更多),而不是让它们处理不当.当未处理的异常情况发生时,你基本上失去了应对这个问题和发送者的描述发送者可能会再得到的能力TimeoutException,而不是他们的Future永远不会完成.一旦确定了明确处理的内容,就可以在定义自定义主管策略时考虑所有其余的异常.这个街区在这里:

OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 10 seconds) {
  case x: Exception => ???
}
Run Code Online (Sandbox Code Playgroud)

您有机Directive会将异常类型映射到故障,该故障定义了从监管角度处理故障的方式.选项是:

  1. 停止 - 完全停止子actor并且不再向其发送任何消息

  2. 恢复 - 恢复失败的孩子,而不是重新启动它,从而保持其当前的内部状态

  3. 重新启动 - 与resume类似,但在这种情况下,抛弃旧实例并构造新实例并重置内部状态(preStart)

  4. 上报 - 将链条升级为主管的父母

所以,假设SQLException您希望恢复并给予您想重新启动的所有其他人,那么您的代码将如下所示:

OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 10 seconds) {
  case x: SQLException => Resume
  case other => Restart
}
Run Code Online (Sandbox Code Playgroud)

现在讨论第二个问题,该问题涉及当Future自身返回Failure响应时该怎么做.在这种情况下,我想这取决于应该发生的事情Future.如果其余的actor本身负责完成http请求(让我们说httpCtx上有一个complete(statusCode:Int, message:String)函数),那么你可以这样做:

   ask(dbActor, ReadCommand(reqCtx, id)).mapTo[SomeObject] onComplete {
    case Success(obj) => reqCtx.complete(200, "All good!")
    case Failure(err:TimeoutException) => reqCtx.complete(500, "Request timed out")
    case Failure(ex) => reqCtx.complete(500, ex.getMessage)
  }
Run Code Online (Sandbox Code Playgroud)

现在,如果上游的另一个actor负责完成http请求,并且您需要响应该actor,则可以执行以下操作:

   val origin = sender
   ask(dbActor, ReadCommand(reqCtx, id)).mapTo[SomeObject] onComplete {
    case Success(obj) => origin ! someResponseObject
    case Failure(ex) => origin ! Status.Failure(ex)
  }
Run Code Online (Sandbox Code Playgroud)

这种方法假设在成功块中,您首先要在响应之前按摩结果对象.如果您不想这样做,并且您希望将结果处理推迟到发件人,那么您可以这样做:

   val origin = sender
   val fut = ask(dbActor, ReadCommand(reqCtx, id))
   fut pipeTo origin
Run Code Online (Sandbox Code Playgroud)