1

我正在尝试遵循最佳实践并在 Akka 中应用错误内核模式。根据这里的报价

如果一个actor携带了非常重要的数据(即如果可以避免,它的状态不会丢失),这个actor应该将任何可能危险的子任务分配给它所监督的子任务,并适当地处理这些子任务的失败。根据请求的性质,最好为每个请求创建一个新的子请求,这样可以简化收集回复的状态管理。这被称为 Erlang 的“错误内核模式”。

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

在这种情况下,如果具有重要状态的参与者由于某种原因重新启动,我是否需要处理来自它的陈旧子项(在重新启动之前创建)的消息?

让我们用例子来说明这一点。

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

A的监督策略被配置为在异常时重新启动它的孩子。

CB的构造函数中创建。

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

现在,让我们假设before cb被发送到并由B A将消息发送ab到处理B。此消息导致B抛出异常,并且由于A的​​监督策略决定B将重新启动。

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

在重新启动之前发送的重新启动B接收是否会重新启动?cbCB

如果是, ( ) 的子项是否会sendercb视为Crestarted 的子项B?演员 ref 的CC'是否相等(假设CC's 的名字相等)?

4

2 回答 2

2

是的,您的 restartedB将收到来自 first 的响应C。如果C正在执行长时间运行的工作并且其父级失败,则在完成其长时间运行的工作B之前实际上不会重新启动。C作为重新启动B的一部分,原件C被停止(未重新启动)并C创建一个新的(您所称的C'),它是重新启动的子项B。然而,第一个C不会是重新启动的孩子B

当第一个C完成时,它的senderref 仍然有效,并且即使它即将重新启动,该响应仍然可以传递到该 refs 邮箱。当B重新启动时,它能够保留重新启动前在其邮箱中的内容,因此它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
    }
  } 
}
于 2014-09-29T18:07:54.193 回答
0

你的问题包含一个矛盾:

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

那么是哪一个呢?是否cb在重新启动之前发送?

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

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

编辑:忘记了第二个问题:如果在重启之前发送了 cb,而 B 实际上收到了它,那么发送者将是ActorRef指向 C 的新实例的一个。sActorRefActors 是 2 个不同的实体。

于 2014-09-29T12:50:54.203 回答