当我在我的Actor的构造函数中安排消息并且在发送消息之前actor失败(Exception)时会发生什么?
preStart()
中启动计时器时,如果演员在失败后重启,我会有两条预定的消息吗?答案 0 :(得分:3)
您的问题的答案如下:
1)是的,只要您使用以scheduleOnce
作为arg的调度程序ActorRef
变体,actor就会收到该消息。因为ActorRef
只是一个基于actor地址的轻量级代理,它可以在目标actor的失败中存活,并且只要它成功重新启动备份并重新绑定到{的地址,它仍会将消息路由到它。 {1}}表示/
2)是的,如果ActorRef
用于ActorRef
中不再显示的路径,则该消息将被发送到deadletter。
3)是的,你会的。如果你在ActorSystem
或者actor(构造函数)的主体中执行它并且actor失败并重新启动,那么调度现在将为同一个preStart
执行两个作业,因此两个请求将最终收到。
显示所有这些内容的小代码。考虑以下演员:
ActorRef
如果您以这种方式测试它:
class TestSchedActor extends Actor{
import context._
override def preStart = {
context.system.scheduler.scheduleOnce(1 second, self, "bar")
}
def receive = {
case "foo" =>
val s:String = null
s.length
case "baz" =>
context stop self
case other =>
println(s"Got $other")
}
}
然后输出为:
val system = ActorSystem("schedtest")
val ref = system.actorOf(Props[TestSchedActor])
ref ! "foo"
这显示#1和#3,因为演员在失败后仍然收到消息,并且在重新启动时再次重新安排时实际收到2。
如果你像这样测试演员:
[ERROR] [04/03/2014 07:58:24.988] [schedtest-akka.actor.default-dispatcher-2] [ akka://schedtest/user/$a] null
java.lang.NullPointerException
at code.TestSchedActor$$anonfun$receive$1.applyOrElse(Asking.scala:27)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:498)
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)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:262)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:975)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1478)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104)
Got bar
Got bar
然后你会看到以下输出:
val system = ActorSystem("schedtest")
val ref = system.actorOf(Props[TestSchedActor])
ref ! "baz"
如果您没有禁用死锁记录。
答案 1 :(得分:1)
我假设你的actor向自己发送一条消息(使用一个计划任务)(使用类似system.actorSelection来解析自己的地址)。 然后: 1)是的; 2)是的; 3)是(此外,如果你在构造函数中启动计时器,你会得到相同的行为)。
为避免所有此类问题,您可以在preStart()中启动计时器,将收到的Cancellable保存到Actor内的局部变量中,然后在postStop()中取消它。 postStop()/ preStart()从preRestart()/ postRestart()调用,因此您的计划任务将在Actor重新启动时重新安排,并在Actor停止时取消。