考虑下面的代码示例。这里父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的异常?
答案 0 :(得分:1)
停止演员"只是停下来",不可能知道孩子是否有飞行中的信息(你不想去那里)。所以要回答你的问题 - 要么优雅地关闭你的孩子,要么准备在停止演员时错过这样的消息。
如果您确实希望始终确保记录此消息,那么try {} catch {}
仍可供您使用,并且在适当的时候使用它也不错。或者
---编辑:优雅停止示例
// parent
child ! PleaseDie
// child
case PleaseDie => context stop self