Akka故障处理和调度程序

时间:2014-04-03 09:10:56

标签: akka scheduler

当我在我的Actor的构造函数中安排消息并且在发送消息之前actor失败(Exception)时会发生什么?

  • 当演员恢复或重新启动时,消息是否会发送,就像什么都没发生一样?
  • 当演员停止时,消息会发送到死信箱吗?
  • 当我在preStart()中启动计时器时,如果演员在失败后重启,我会有两条预定的消息吗?

2 个答案:

答案 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停止时取消。