我有一个演员有藏匿处。有时,当它崩溃时,它会丢失所有隐藏的消息。我发现这取决于我使用什么监督逻辑。
我写了一个简单的例子。
有藏匿的演员:
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。有什么办法可以解决吗?
答案 0 :(得分:1)
我不确定是否可以使BackoffSupervisor
下的BackoffSupervisor
正确发送隐藏的消息,而无需进行一些自定义重新实现工作。
正如您已经指出的那样,restart
自己做的{{1}}绕过了标准actor生命周期。实际上,它在BackoffOnRestartSupervisor源代码中已明确指出:
无论最终指令是什么,我们都会将所有重新启动转换为我们的 自己重新启动,这涉及到停止孩子。
如果您还没有阅读有关reported issue的信息,那么它会进行有关Backoff.onFailure的讨论:
Backoff.onStop还将提供所需的BackoffSupervisor功能,但不幸的是,它具有自己的用例,不会被异常触发。