我应该如何处理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 => ???
}
}
}
}
}
很高兴得到你的想法,提前谢谢!
答案 0 :(得分:7)
根据您的代码示例中的问题,我可以在此处看到几个问题:
当我在如何处理异常的定义中覆盖默认的主管行为时,我可以做些什么类型的事情?
- 醇>
使用
ask
时,如果我在等待的Failure
上获得Future
结果,我可以执行哪些类型的操作?
让我们先从第一个问题开始(通常是一个好主意)。当您覆盖默认的主管策略时,您可以更改如何处理子actor中某些类型的未处理异常,以了解如何处理该失败的子actor。前一句中的关键词是unhandled
。对于正在执行请求/响应的actor,您实际上可能希望处理(捕获)特定异常并返回某些响应类型(或者在上游未来失败,稍后更多),而不是让它们处理不当。当发生未处理的异常时,您基本上无法使用问题描述来回复发件人,而发件人可能会获得TimeoutException
,因为他们的Future
永远不会完成。一旦确定了明确处理的内容,就可以在定义自定义主管策略时考虑所有其余的异常。在这个街区内:
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 10 seconds) {
case x: Exception => ???
}
您有机会将异常类型映射到失败Directive
,该失败定义了从监管角度处理失败的方式。选项包括:
停止 - 完全停止儿童演员并且不再向其发送任何消息
恢复 - 恢复失败的孩子,而不是重新启动它,从而保持其当前的内部状态
重新启动 - 与resume类似,但在这种情况下,旧实例将被丢弃并构建一个新实例并重置内部状态(preStart)
升级 - 将链条升级为主管的父母
所以,假设你想要恢复SQLException
并给予你想要重启的所有其他人,那么你的代码将如下所示:
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 10 seconds) {
case x: SQLException => Resume
case other => Restart
}
现在提出第二个问题,该问题与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)
}
现在如果上游的另一个演员负责完成http请求并且您需要回复该演员,那么您可以这样做:
val origin = sender
ask(dbActor, ReadCommand(reqCtx, id)).mapTo[SomeObject] onComplete {
case Success(obj) => origin ! someResponseObject
case Failure(ex) => origin ! Status.Failure(ex)
}
此方法假设在成功块中您首先要在响应之前按摩结果对象。如果您不想这样做,并且想要将结果处理推迟给发件人,那么您可以这样做:
val origin = sender
val fut = ask(dbActor, ReadCommand(reqCtx, id))
fut pipeTo origin
答案 1 :(得分:3)
有一个激活器(http://www.typesafe.com/activator)模板,它显示了将询问和监督联系在一起的一个很好的例子:http://www.typesafe.com/activator/template/akka-supervision。
答案 2 :(得分:0)
对于更简单的系统,人们可能希望捕获并转发所有错误。为此我创建了这个小函数来包装接收方法,而不用担心监督:
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
等。显然,这不会处理异步代码抛出的异常。