我正在尝试遵循最佳实践并在Akka中应用错误内核模式。根据{{3}}的引用:
如果一个演员携带非常重要的数据(即,如果可以避免,其状态不会丢失),该演员应该向其监督的儿童采购任何可能存在危险的子任务,并在适当时处理这些儿童的失败。根据请求的性质,最好为每个请求创建一个新子项,这样可以简化收集回复的状态管理。这被称为Erlang的“错误内核模式”。
...创建子项并将容易出错的工作委托给他们是一个好主意,将重要的状态集中在父/主管演员身上。
在这种情况下,如果具有重要状态的actor由于某种原因重新启动,我是否需要处理来自其过时子(在重新启动之前创建)的消息?
让我们举例说明。
让asuume我有演员3个演员:A
(是B
的父母/主管),B
(是C
的父母/主管,包含重要状态)和C
。
A
的监督策略配置为在例外情况下重启其子女。
C
在B
的构造函数中创建。
然后假设消息bc
从B
发送到C
。 C
开始处理它(让我们想象它会在那里运行长时间运行的计算),一旦完成,将使用B
回复cb
。
现在,我们假设 cb
发送给B
A
并由ab
B
处理后发送消息B
到A
。此消息会导致B
抛出异常,并且由于B
的监督策略决策C
将重新启动。
B
C'
的孩子将在B
重启期间停止(将在B
的构造函数中创建新的cb
)。
重新启动C
会从B
重新启动之前发送的sender
收到cb
吗?
如果是,C
(B
)的C
会被视为已重新启动C'
的孩子吗?并且C
和C'
的参与者是否相等(假设{{1}}和{{1}}的名称相等)?
答案 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个不同的实体。