处理actor中preStart中的异常

时间:2015-12-10 08:32:59

标签: scala akka actor

我有一个服务,主管负责构建子actor并处理它们的异常。

ServiceMain -> Supervisor -> DiscoveryActor

要构建DiscoveryActor,请拨打以下内容

Await.result(supervisor ? (Props[Discovery], "Discovery"), Duration.create(60, SECONDS)) match {
    case actor: ActorRef =>
      discoveryActor = actor

    case ex: Exception =>
      logger.error("Failed to initialize discovery actor", ex)
      sys.exit(1)
}

此代码在Supervisor

中处理了哪些内容
def receive = {
  case p: Props => sender() ! context.actorOf(p)

  case (p: Props, s: String) => sender() ! context.actorOf(p, s)
}

如果DiscoveryActor无法按照配置研究主机,则preStart()会在ApiConnectionException中抛出异常。行为者抛出异常ActorInitializationException,由akka捕获并变为override val supervisorStrategy = AllForOneStrategy() { case _: Exception => Escalate }

我已经厌倦了在Await和superviseStrategy中捕获此异常,如下所示

400 Bad Request Show explanation Loading time: 645
Request headers 
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.73 Safari/537.36
Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
Content-Type: multipart/form-data 
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Response headers 
Date: Thu, 10 Dec 2015 08:30:07 GMT 
Server: Apache 
X-Request-Id: 8e80edd8-ff10-44f2-9235-6b8d307c179b
X-Runtime: 0.002612
X-Powered-By: Phusion Passenger 4.0.58
Content-Length: 38 
Status: 400 Bad Request
Connection: close
Content-Type: application/json; charset=utf-8 

但是这些都没有设法抓住它,我试图做的是捕获这样的异常并退出应用程序。

如果有人能够指出我出错的地方或我错过了什么,那么我将非常感激!

1 个答案:

答案 0 :(得分:3)

我简化了你的代码只是为了直接找到问题的根源。您可以将其复制并粘贴到编辑器中。它使用 ScalaTest 套件。

SupervisorStrategy actor 中定义的

Supervisor确实捕获Discovery方法preStart方法引发的异常。您可能希望仔细查看自己的代码。

您的Await块正在尝试捕获异常,但在此上下文中不可能。 ExceptionDiscovery actor引发,而不是作为消息发送。问你使用的模式(?)只是等待消息到达。只使用SupervisorStrategy可以让你回到抛出的异常。您可以向应用程序Guardian actor发送消息,告知初始化失败,以便应用程序退出,而不是升级Supervisor中的异常。或直接在Supervisor中进行操作。

import java.util.concurrent.TimeUnit    
import akka.actor.SupervisorStrategy.Escalate
import akka.actor._
import akka.pattern.ask
import akka.testkit.{ImplicitSender, TestKit}
import akka.util.Timeout
import org.scalatest.{BeforeAndAfterAll, FunSuiteLike, Matchers}

import scala.concurrent.Await

abstract class ActorSuite(systemName: String)
  extends TestKit(ActorSystem(systemName))
  with FunSuiteLike
  with ImplicitSender
  with Matchers
  with BeforeAndAfterAll {

  override def afterAll {
    TestKit.shutdownActorSystem(system)
  }
}

class FailingActorInitializationSuite extends ActorSuite("failing-system") {


  test("run it") {

    val supervisor = system.actorOf(Props[Supervisor])
    var discoveryActor: ActorRef = null

    implicit val timeout = Timeout(60, TimeUnit.SECONDS)

    Await.result(
      supervisor ?(Props[Discovery], "Discovery"), timeout.duration) match {
      case actor: ActorRef =>
        discoveryActor = actor
    }
  }
}

class Supervisor extends Actor with ActorLogging {

  override val supervisorStrategy =
    AllForOneStrategy() {
      case e: Exception =>
        log.error(s"Caught an exception [${e.getCause.getMessage}] and escalating")
        Escalate
    }

  override def receive: Receive = {
    case (p: Props, s: String) => sender() ! context.actorOf(p, s)
  }
}

class Discovery extends Actor {

  override def preStart(): Unit = {
    super.preStart()
    throw new RuntimeException("Can't create")
  }

  override def receive: Actor.Receive = {
    case _ =>
  }
}