在Akka中出现错误内核和监督:来自陈旧孩子的消息会被传递给重新启动的演员吗?

时间:2014-09-29 08:18:49

标签: scala akka actor error-kernel akka-supervision

我正在尝试遵循最佳实践并在Akka中应用错误内核模式。根据{{​​3}}的引用:

  

如果一个演员携带非常重要的数据(即,如果可以避免,其状态不会丢失),该演员应该向其监督的儿童采购任何可能存在危险的子任务,并在适当时处理这些儿童的失败。根据请求的性质,最好为每个请求创建一个新子项,这样可以简化收集回复的状态管理。这被称为Erlang的“错误内核模式”。

...创建子项并将容易出错的工作委托给他们是一个好主意,将重要的状态集中在父/主管演员身上。

在这种情况下,如果具有重要状态的actor由于某种原因重新启动,我是否需要处理来自其过时子(在重新启动之前创建)的消息?

让我们举例说明。

让asuume我有演员3个演员:A(是B的父母/主管),B(是C的父母/主管,包含重要状态)和C

A的监督策略配置为在例外情况下重启其子女。

CB的构造函数中创建。

然后假设消息bcB发送到CC开始处理它(让我们想象它会在那里运行长时间运行的计算),一旦完成,将使用B回复cb

现在,我们假设 cb发送给B A并由ab B处理后发送消息BA 。此消息会导致B抛出异常,并且由于B的监督策略决策C将重新启动。

B C'的孩子将在B重启期间停止(将在B的构造函数中创建新的cb)。

重新启动C会从B重新启动之前发送的sender收到cb吗?

如果是,CB)的C会被视为已重新启动C'的孩子吗?并且CC'的参与者是否相等(假设{{1}}和{{1}}的名称相等)?

2 个答案:

答案 0 :(得分:2)

是的,重新启动的B将从第一个C收到回复。如果C正在执行长时间运行的工作并且其父级失败,那么B实际上将不会重新启动C,直到B完成其长时间运行的工作。作为重新启动C的一部分,原始C已停止(未重新启动),并且创建了一个新的C'(您正在调用的B)重新启动C。但是,第一个B不会是重新启动的C的子项。

当第一个sender完成时,其B ref仍然有效,即使即将重新启动,此响应仍可以传递到该refs邮箱。重新启动cb时,它可以在重新启动之前保留其邮箱中的内容,从而在开始备份后立即接收并处理import akka.actor._ import concurrent.duration._ object RestartExample extends App{ case object Start case object AB case object BC case object CB val system = ActorSystem("test") val a = system.actorOf(Props[A]) a ! Start class A extends Actor{ val b = context.actorOf(Props[B], "myb") import context.dispatcher def receive = { case Start => b ! Start context.system.scheduler.scheduleOnce(3 seconds, b, AB) } } class B extends Actor{ println("new B actor instance created") val c = context.actorOf(Props[C], "myc") def receive = { case Start => c ! BC case CB => println("got a CB from C") case AB => throw new RuntimeException("foo") } } class C extends Actor{ println("new C actor instance created") def receive = { case BC => Thread.sleep(10000) // simulating long running behavior println("done with long processing...") sender ! CB } } } 消息。

我起草了一个代码示例来展示这种行为:

{{1}}

答案 1 :(得分:0)

你的问题包含矛盾:

“现在,我们假设在将cb发送到B并由B处理之前” “将重新启动B从B重新启动之前发送的C接收cb”

那是哪一个?是否在重启之前发送了cb

如果C在发送消息之前重新启动,则它将丢失。如果它是在重新启动之前发送的,但是没有由B处理,则它将在B的邮箱中,并且B的新实例将接收它。

基本上,我建议你设计一个消息一丢失就不会崩溃的流程。在使用Akka时,您应始终假设任何消息都可能随时丢失。

编辑:忘记了第二个问题:如果cb是在重启之前发送的,而B实际收到它,则发件人将是ActorRef指向新的C. ActorRef s和{{ 1}}是2个不同的实体。