由Backoff监督的Actor重启后丢失了隐藏的消息

时间:2018-12-26 14:27:20

标签: scala akka actor akka-supervision

我有一个演员有藏匿处。有时,当它崩溃时,它会丢失所有隐藏的消息。我发现这取决于我使用什么监督逻辑。

我写了一个简单的例子。

有藏匿的演员:

case object WrongMessage
case object TestMessage
case object InitialMessage

class TestActor extends Actor with Stash {
  override def receive: Receive = uninitializedReceive

  def uninitializedReceive: Receive = {
    case TestMessage =>
      println(s"stash test message")
      stash()

    case WrongMessage =>
      println(s"wrong message")
      throw new Throwable("wrong message")

    case InitialMessage =>
      println(s"initial message")
      context.become(initializedReceive)
      unstashAll()
  }

  def initializedReceive: Receive = {
    case TestMessage =>
      println(s"test message")
  }
}

在以下代码中,TestActor 从不接收隐藏的TestMessage

object Test1 extends App {
  implicit val system: ActorSystem = ActorSystem()
  val actorRef = system.actorOf(BackoffSupervisor.props(Backoff.onFailure(
      Props[TestActor], "TestActor", 1 seconds, 1 seconds, 0
  ).withSupervisorStrategy(OneForOneStrategy()({
    case _ => SupervisorStrategy.Restart
  }))))
  actorRef ! TestMessage
  Thread.sleep(5000L)
  actorRef ! WrongMessage
  Thread.sleep(5000L)
  actorRef ! InitialMessage
}

但是此代码运行良好:

class SupervisionActor extends Actor {
  val testActorRef: ActorRef = context.actorOf(Props[TestActor])

  override def supervisorStrategy: SupervisorStrategy = OneForOneStrategy()({
    case _ => SupervisorStrategy.Restart
  })

  override def receive: Receive = {
    case message => testActorRef forward message
  }
}

object Test2 extends App {
  implicit val system: ActorSystem = ActorSystem()
  val actorRef = system.actorOf(Props(classOf[SupervisionActor]))
  actorRef ! TestMessage
  Thread.sleep(5000L)
  actorRef ! WrongMessage
  Thread.sleep(5000L)
  actorRef ! InitialMessage
}

我调查了消息来源,发现演员监督使用 由LocalActorRef.restart支持的system dispatcher logic方法,但是BackoffSupervisor仅在creates a new actor之后termination of the old one。有什么办法可以解决吗?

1 个答案:

答案 0 :(得分:1)

我不确定是否可以使BackoffSupervisor下的BackoffSupervisor正确发送隐藏的消息,而无需进行一些自定义重新实现工作。

正如您已经指出的那样,restart自己做的{{1}}绕过了标准actor生命周期。实际上,它在BackoffOnRestartSupervisor源代码中已明确指出:

  

无论最终指令是什么,我们都会将所有重新启动转换为我们的   自己重新启动,这涉及到停止孩子。

如果您还没有阅读有关reported issue的信息,那么它会进行有关Backoff.onFailure的讨论:

Backoff.onStop还将提供所需的BackoffSupervisor功能,但不幸的是,它具有自己的用例,不会被异常触发。