1

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

我写了一个简单的例子。

藏匿的演员:

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 永远不会收到 stashed 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方法,但只是在旧演员终止创建了一个新演员。有没有办法解决它?BackoffSupervisor

4

1 回答 1

1

我不确定是否可以在不进行一些自定义重新实现工作的情况restart下正确发送隐藏的消息。BackoffSupervisor

正如您已经指出的那样,BackoffSupervisor它自己restart绕过了标准的演员生命周期。事实上,在BackoffOnRestartSupervisor源代码中明确指出:

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

如果您还没有阅读过这个报告的问题,它有一个相关的讨论:Backoff.onFailure的问题。

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

于 2018-12-28T17:34:09.270 回答