当失败时,谁的责任是创造Akka演员的孩子?

时间:2013-06-26 07:43:55

标签: scala akka actor

Akka的文档正确引用说:

  

重启期间的精确事件顺序如下:   暂停演员(这意味着它不会处理正常   消息,直到恢复),并递归暂停所有孩子。

误导性的一句话说:

  

恢复演员恢复其所有下属,重新启动演员   需要重新启动其所有下属,同样终止一个actor也将终止其所有下属

我怀疑我们有责任在preStart方法中创建子(ren),因为Akka的术语 RESTART 不是reSTART,除非你在他们的中递归和明确地创建子项父preStart()方法。

示例(使用Akka 2.0& 2.2-SNAPSHOT):无论我尝试什么,孩子总是刚刚停止,从未在此测试用例中重新启动。我创建了Supervisor - > First - > Second关系并在Supervisor中抛出异常。会发生什么情况supervisor重新启动,First& Second停了。

  test("restart test") {
    val system = ActorSystem("test")
    val supervisor = system.actorOf(Props(new Supervisor), "supervisor")
    supervisor ! CREATE(Props(new First), "first")
    Thread.sleep(500)

    val first = system.actorFor("akka://test/user/supervisor/first")
    first ! CREATE(Props(new Second), "second")
    Thread.sleep(500)
    supervisor ! WTF

    Thread.sleep(20000)
  }

  case object WTF
  case class CREATE(p: Props, name: String)

  class Supervisor extends Actor {
    override val supervisorStrategy =
      OneForOneStrategy(maxNrOfRetries = 10) {
        case _: IllegalStateException       => Restart
        case _: IllegalArgumentException    => Stop
        case _: Exception                   => Restart
    }
    override def preStart() {
      println(s"$self starts")
    }
    override def postStop() {
      println(s"$self stopped")
    }
    override def receive = {
      case WTF => println("throwing exception"); throw new IllegalStateException()
      case CREATE(p, name) => context.actorOf(p, name)
    }
  }
  class First extends Actor {
    override def preStart() {
      println(s"$self starts")
    }
    override def postStop() {
      println(s"$self stopped")
    }
    override def receive = {
      case WTF => println("throwing exception"); throw new IllegalStateException()
      case CREATE(p, name) => context.actorOf(p, name)
    }
  }
  class Second extends Actor {
    override def preStart() {
      println(s"$self starts")
    }
    override def postStop() {
      println(s"$self stopped")
    }
    override def receive = {
      case WTF => println("throwing exception"); throw new IllegalStateException()
      case CREATE => sender ! "ok"
    }
  }
  

演员[akka:// test / user / supervisor#1599926629]开始   演员[akka:// test / user / supervisor / first#2012011668]开始   演员[akka:// test / user / supervisor / first / second#1750038710]开始

     

抛出异常演员[akka:// test / user / supervisor#1599926629]   停止[错误] [06/26/2013 11:11:16.899]   [test-akka.actor.default-dispatcher-4] [akka:// test / user / supervisor]   null java.lang.IllegalStateException at   com.fg.mail.smtp.IntegrationSuite $主管$$ anonfun $获得$ 1.applyOrElse(IntegrationSuite.scala:40)   at akka.actor.ActorCell.receiveMessage(ActorCell.scala:498)at at at   akka.actor.ActorCell.invoke(ActorCell.scala:456)at   akka.dispatch.Mailbox.processMailbox(Mailbox.scala:237)at   akka.dispatch.Mailbox.run(Mailbox.scala:219)at   akka.dispatch.ForkJoinExecutorConfigurator $ AkkaForkJoinTask.exec(AbstractDispatcher.scala:386)   在   scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:262)   在   scala.concurrent.forkjoin.ForkJoinPool $ WorkQueue.runTask(ForkJoinPool.java:975)   在   scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1478)   在   scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104)

     

演员[akka:// test / user / supervisor / first / second#1750038710]停了下来   演员[akka:// test / user / supervisor / first#2012011668]停了下来   演员[akka:// test / user / supervisor#1599926629]开始

1 个答案:

答案 0 :(得分:6)

你的怀疑是正确的。如果您仔细查看http://doc.akka.io/docs/akka/snapshot/general/supervision.html上重启过程的7步说明,您会看到:

  

2。 ...默认为所有孩子发送终止请求......

  

6。向所有未被杀死的孩子发送重启请求

所以,你需要覆盖父的preRestart钩子来阻止Akka杀死孩子,或者覆盖postRestart来重新创建刚杀死的所有孩子。

您选择的确实取决于您的应用程序的语义。有时杀死整个层次结构并从空白的平板开始是有用的,有时候不是。