【问题标题】:Whose responsibility is creating Akka actor's children when it fails?失败时创建 Akka actor 的孩子是谁的责任?
【发布时间】:2013-06-23 06:03:55
【问题描述】:

Akka 的文档正确引用说:

重新启动期间的确切事件顺序如下: 暂停actor(这意味着它不会正常处理 消息直到恢复),并递归挂起所有子节点。

一个误导性的引用说:

恢复一个actor会恢复它的所有下属,重启一个actor 需要重新启动其所有下属,同样终止一个actor也会终止其所有下属

我怀疑在 preStart 方法中创建子项是我们的责任,因为 Akka 的术语 RESTART 不是 reSTART 除非您在其父项 @ 中递归且显式地创建子项987654322@方法。

示例(使用 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] 开始 Actor[akka://test/user/supervisor/first#2012011668] 开始 Actor[akka://test/user/supervisor/first/second#1750038710] 开始

抛出异常 Actor[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 在 com.fg.mail.smtp.IntegrationSuite$Supervisor$$anonfun$receive$1.applyOrElse(IntegrationSuite.scala:40) 在 akka.actor.ActorCell.receiveMessage(ActorCell.scala:498) 在 akka.actor.ActorCell.invoke(ActorCell.scala:456) 在 akka.dispatch.Mailbox.processMailbox(Mailbox.scala:237) 在 akka.dispatch.Mailbox.run(Mailbox.scala:219) 在 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] 停止 Actor[akka://test/user/supervisor#1599926629] 开始

【问题讨论】:

    标签: scala akka actor


    【解决方案1】:

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

    2 。 ...默认向所有子节点发送终止请求...

    6 .向所有未被杀死

    的孩子发送重启请求

    因此,您需要覆盖父级的 preRestart 挂钩以阻止 Akka 杀死子级,或覆盖 postRestart 以重新创建刚刚杀死的所有子级。

    您选择哪个实际上取决于您的应用程序的语义。有时杀死整个层次结构并从头开始很有用,有时则不然。

    【讨论】:

    • 很遗憾,没有第三个选项可以隐式地重新启动子级...如果您考虑一下,形成层次结构的唯一安全方法是在其父级的 preStart() 方法中创建后代actor。任何其他方式都很难实现。
    • 文档非常含糊,因为他们到处都在写“重新启动”,它实际上意味着“调用” preRestart 和 postRestart 生命周期方法,但您有责任关心实际的重新“启动”
    • 没有?如果您在构造函数或 preStart 中创建子代,则在重新启动父代时会自动重新创建子代。
    • Viktor:是的,它们是……但是 akka 文档的术语 restart 并不是没有 RESTART,除非你按照你说的去做 - 这在整个文档中完全没有
    • 顺便说一句,除了抛出异常之外,您知道如何分段重启 Actor 吗?我找不到在处理消息的过程中调用抛出异常效果的方法。考虑到你在顶级演员中,调用 context.stop(self) 来停止它的所有孩子,但是如何重新启动自己?
    猜你喜欢
    • 2016-05-27
    • 1970-01-01
    • 2023-03-29
    • 2018-07-17
    • 2015-05-07
    • 1970-01-01
    • 1970-01-01
    • 2017-02-12
    • 2023-04-02
    相关资源
    最近更新 更多