如果父actor停止,则不会记录子actor actor消息处理期间的异常

时间:2014-09-09 09:57:26

标签: akka actor

考虑下面的代码示例。这里父actor(ActorA)向子actor(ActorB)发送消息然后停止self。子actor接收消息然后抛出异常。我期待由actor系统进行一些异常记录,但是没有异常记录(参见示例输出1)。

我理解这是由于父母演员的停止而发生的,如果我不停止父母,则会记录异常(参见示例输出2)。

import akka.actor.Actor
import akka.actor.ActorSystem
import akka.actor.Props
import akka.actor.OneForOneStrategy
import akka.actor.SupervisorStrategy.Stop

object AkkaTest extends App {

  ActorSystem("AkkaTest").actorOf(Props[ActorA]) ! 3

}

class ActorA extends Actor {

  def receive = {
    case i: Int => {
      context.actorOf(Props[ActorB]) ! i 
      context.stop(self)
    }
  }

  override val supervisorStrategy = OneForOneStrategy() {
    case throwable: Throwable  => {
      println("ActorA - supervision strategy - exception in child actor")
      Stop
    }
  }

  override def preStart = println("ActorA - started")

  override def postStop = println("ActorA - stopped")

  override def preRestart(th: Throwable, msg: Option[Any]) = println("ActorA - restarted")

}

class ActorB extends Actor {

  def receive = {
    case i: Int => {
      println("ActorB - processing msg - " + i)
      throw new Exception("boom")
    }
  }

  override def preStart = println("ActorB - started")

  override def postStop = println("ActorB - stopped")

  override def preRestart(th: Throwable, msg: Option[Any]) = println("ActorB - restarted")

}

样本输出1

ActorA - started
ActorB - started
ActorB - processing msg - 3
ActorB - stopped
ActorA - stopped

样本输出2

ActorA - started
ActorB - started
ActorB - processing msg - 3
ActorA - supervision strategy - exception in child actor
ActorB - stopped
[ERROR] [09/09/2014 10:43:08.079] [AkkaTest-akka.actor.default-dispatcher-5] [akka://AkkaTest/user/$a/$a] boom
java.lang.Exception: boom
    at ActorB$$anonfun$receive$2.applyOrElse(AkkaTest.scala:42)
    at akka.actor.Actor$class.aroundReceive(Actor.scala:465)
    at ActorB.aroundReceive(AkkaTest.scala:37)
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:516)
    at akka.actor.ActorCell.invoke(ActorCell.scala:487)
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:238)
    at akka.dispatch.Mailbox.run(Mailbox.scala:220)
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:393)
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

我是否遗漏了任何actor系统配置,因为父节点停止后没有记录子actor参与者异常?是否可以保证在上述场景中记录任何子actor的异常?

1 个答案:

答案 0 :(得分:1)

停止演员"只是停下来",不可能知道孩子是否有飞行中的信息(你不想去那里)。所以要回答你的问题 - 要么优雅地关闭你的孩子,要么准备在停止演员时错过这样的消息。

如果您确实希望始终确保记录此消息,那么try {} catch {}仍可供您使用,并且在适当的时候使用它也不错。或者

---编辑:优雅停止示例

// parent
child ! PleaseDie


// child
case PleaseDie => context stop self