首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用ask模式和监控来处理异常

如何使用ask模式和监控来处理异常
EN

Stack Overflow用户
提问于 2013-07-22 16:22:06
回答 2查看 3.5K关注 0票数 9

我应该如何处理DbActor在这里抛出的异常?我不确定如何处理它,是否应该通过管道处理失败的情况?

代码语言:javascript
运行
复制
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 => ???
        }
      }
    }
  }
}

将很高兴得到您的想法,提前感谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-07-22 21:04:35

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

  1. 当我覆盖如何处理异常的定义中的默认主管行为时,我可以执行哪些类型的操作?

  1. 使用ask时,当我在等待的Future上获得Failure结果时,可以执行哪些类型的操作?

让我们先从第一个问题开始(通常是个好主意)。当您覆盖默认的主管策略时,您可以根据如何处理失败的子执行元来更改子执行元中某些类型的未处理异常的处理方式。前一句话中的关键词是unhandled。对于正在进行请求/响应的参与者,您可能实际上希望处理(捕捉)特定的异常并返回特定的响应类型(或者在上游将来失败,稍后再详细介绍),而不是让它们不被处理。当一个未处理的异常发生时,你基本上失去了向发送者回复问题描述的能力,然后发送者可能会得到一个TimeoutException,因为他们的Future永远不会完成。一旦您弄清楚了显式处理的内容,那么您就可以在定义自定义主管策略时考虑所有其他例外情况。在这个代码块中:

代码语言:javascript
运行
复制
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 10 seconds) {
  case x: Exception => ???
}

您有机会将异常类型映射到故障Directive,它定义了如何从监督的角度处理故障。选项包括:

  1. Stop -完全停止该子执行元,并且不再向其发送任何消息

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

  1. Restart -类似于resume,但在这种情况下,将丢弃旧实例,构建一个新实例,内部状态为reset (preStart)

  1. Escalate -将链向上升级到supervisor

的父级

因此,假设给定一个您想要恢复的SQLException,并且给定所有其他您想要重新启动的a,那么您的代码将如下所示:

代码语言:javascript
运行
复制
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 10 seconds) {
  case x: SQLException => Resume
  case other => Restart
}

现在来看第二个问题,即当Future本身返回Failure响应时该如何处理。在这种情况下,我猜这取决于Future的结果。如果rest参与者本身负责完成http请求(假设httpCtx有一个complete(statusCode:Int, message:String)函数),那么您可以这样做:

代码语言:javascript
运行
复制
   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)
  }

现在,如果上游的另一个参与者负责完成http请求,而您需要响应该参与者,您可以这样做:

代码语言:javascript
运行
复制
   val origin = sender
   ask(dbActor, ReadCommand(reqCtx, id)).mapTo[SomeObject] onComplete {
    case Success(obj) => origin ! someResponseObject
    case Failure(ex) => origin ! Status.Failure(ex)
  }

这种方法假设在成功块中,您首先希望在响应之前处理结果对象。如果你不想这样做,并且你想把结果的处理交给发送者,那么你可以这样做:

代码语言:javascript
运行
复制
   val origin = sender
   val fut = ask(dbActor, ReadCommand(reqCtx, id))
   fut pipeTo origin
票数 7
EN

Stack Overflow用户

发布于 2015-01-16 21:06:56

对于更简单的系统,可能需要捕获并转发所有错误。为此,我创建了这个小函数来包装receive方法,而不考虑监督:

代码语言:javascript
运行
复制
  import akka.actor.Actor.Receive
  import akka.actor.ActorContext
  /**
   * Meant for wrapping the receive method with try/catch.
   * A failed try will result in a reply to sender with the exception.
   * @example
   *          def receive:Receive = honestly {
   *            case msg => sender ! riskyCalculation(msg)
   *          }
   *          ...
   *          (honestActor ? "some message") onComplete {
   *            case e:Throwable => ...process error
   *            case r:_ => ...process result
   *          }
   * @param receive
   * @return Actor.Receive
   *
   * @author Bijou Trouvaille
   */
    def honestly(receive: =>Receive)(implicit context: ActorContext):Receive = { case msg =>
      try receive(msg) catch { case error:Throwable => context.sender ! error }
    }

然后你可以把它放到一个包文件中,然后导入一个la akka.pattern.pipe等等。显然,这不会处理异步代码抛出的异常。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17782868

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档