Akka故障处理和调度程序
当我在Actor的构造函数中调度消息,并且Actor在消息发送之前失败(异常)时,会发生什么Akka故障处理和调度程序,akka,scheduler,Akka,Scheduler,当我在Actor的构造函数中调度消息,并且Actor在消息发送之前失败(异常)时,会发生什么 当actor恢复或重新启动时,消息是否会像什么都没有发生一样发送 当演员停止时,消息会发送到死信箱吗 当我在preStart()中启动计时器时,当参与者在故障后重新启动时,是否会有两条预定消息 您的问题的答案如下: 1) 是的,只要您使用以ActorRef为参数的调度器scheduleOnce变量,参与者就会收到消息。由于ActorRef只是一个基于参与者地址的轻量级代理,因此只要它成功地重新启动备份
- 当actor恢复或重新启动时,消息是否会像什么都没有发生一样发送
- 当演员停止时,消息会发送到死信箱吗
- 当我在
中启动计时器时,当参与者在故障后重新启动时,是否会有两条预定消息preStart()
- 您的问题的答案如下:
1) 是的,只要您使用以
ActorRef
为参数的调度器scheduleOnce
变量,参与者就会收到消息。由于ActorRef
只是一个基于参与者地址的轻量级代理,因此只要它成功地重新启动备份并重新绑定到ActorRef
表示的地址,它就可以在目标参与者失败后生存,并仍然将消息路由到它/
2) 是的,如果ActorRef
用于ActorSystem
中不再表示的路径,则消息将改为发送到死信
3) 是的,你会的。如果您在pretart
中或在actor(构造函数)的主体中执行此操作,并且actor失败并重新启动,那么计划的actor现在将为同一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"
那么输出将是:
[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
这显示了#1和#3,因为参与者在失败后仍然收到消息,并且在重新启动消息时再次重新调度消息时实际收到了2
如果你像这样测试演员:
val system = ActorSystem("schedtest")
val ref = system.actorOf(Props[TestSchedActor])
ref ! "baz"
然后您将看到以下输出:
[INFO] [04/03/2014 08:01:14.199] [schedtest-akka.actor.default-dispatcher-2] [akka://schedtest/user/$a] Message [java.lang.String] from
Actor[akka://schedtest/user/$a#687201705] to Actor[akka://schedtest/user/$a#687201705] was
not delivered. [1] dead letters encountered. This logging can be turned off or adjusted
with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
如果您没有禁用死信日志记录。您的问题的答案如下: 1) 是的,只要您使用以
ActorRef
为参数的调度器scheduleOnce
变量,参与者就会收到消息。由于ActorRef
只是一个基于参与者地址的轻量级代理,因此只要它成功地重新启动备份并重新绑定到ActorRef
表示的地址,它就可以在目标参与者失败后生存,并仍然将消息路由到它/
2) 是的,如果ActorRef
用于ActorSystem
中不再表示的路径,则消息将改为发送到死信
3) 是的,你会的。如果您在pretart
中或在actor(构造函数)的主体中执行此操作,并且actor失败并重新启动,那么计划的actor现在将为同一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"
那么输出将是:
[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
这显示了#1和#3,因为参与者在失败后仍然收到消息,并且在重新启动消息时再次重新调度消息时实际收到了2
如果你像这样测试演员:
val system = ActorSystem("schedtest")
val ref = system.actorOf(Props[TestSchedActor])
ref ! "baz"
然后您将看到以下输出:
[INFO] [04/03/2014 08:01:14.199] [schedtest-akka.actor.default-dispatcher-2] [akka://schedtest/user/$a] Message [java.lang.String] from
Actor[akka://schedtest/user/$a#687201705] to Actor[akka://schedtest/user/$a#687201705] was
not delivered. [1] dead letters encountered. This logging can be turned off or adjusted
with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
假设您没有禁用死信日志记录。我假设您的参与者(使用计划任务)向自己发送消息(使用类似system.actorSelection的内容来解析自己的地址)。 然后: 1) 对,; 2) 对,; 3) 是(此外,如果您在构造函数中启动计时器,您将获得相同的行为)
为了避免所有这些问题,可以在preStart()中启动计时器,将收到的cancelable保存到Actor内部的局部变量中,然后在postStop()中取消它。postStop()/preStart()是从preRestart()/poststart()调用的,因此计划的任务将在Actor重新启动时重新安排,并在Actor停止时取消。我假设您的Actor(使用计划的任务)向自身发送消息(使用类似system.actorSelection的方法来解析自身地址)。 然后: 1) 对,; 2) 对,; 3) 是(此外,如果您在构造函数中启动计时器,您将获得相同的行为)
为了避免所有这些问题,可以在preStart()中启动计时器,将收到的cancelable保存到Actor内部的局部变量中,然后在postStop()中取消它。postStop()/preStart()是从preRestart()/poststart()调用的,因此计划的任务将在Actor重新启动时重新安排,并在Actor停止时取消。感谢这两个答案以及大量详细信息:)。我不知道一个
ActorRef
可以“生存”失败和其他东西。谢谢你的两个答案和大量详细信息:)。我不知道一个ActorRef
可以“生存”失败和其他东西。