Ядро ошибок и наблюдение в Akka: будут ли сообщения от устаревших детей доставляться перезапущенному субъекту?
Я пытаюсь следовать рекомендациям и применять шаблон ядра ошибок в Akka. Согласно этой цитате отсюда:
Если один субъект несет очень важные данные (т.е. его состояние не должно быть потеряно, если его можно избежать), этот субъект должен найти любые потенциально опасные подзадачи для детей, которых он контролирует, и соответствующим образом обработать ошибки этих детей. В зависимости от характера запросов, может быть лучше создать новый дочерний элемент для каждого запроса, что упрощает управление состоянием для сбора ответов. Это известно как "шаблон ядра ошибки" от Erlang.
... это хорошая идея - создавать дочерние элементы и делегировать им подверженную ошибкам работу, концентрируя важное состояние в акторе родителя / супервизора.
В этом сценарии, если субъект с важным состоянием по какой-то причине перезапускается, нужно ли обрабатывать сообщения от его устаревших потомков (которые были созданы до перезапуска)?
Давайте проиллюстрируем это на примере.
Позвольте, у меня есть актеры 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'
имена равны)?
2 ответа
Да, ваш перезапущен B
получит ответ от первого C
, Если C
выполняет длительную работу, и его родитель не работает, перезапуск B
на самом деле не произойдет, пока C
закончил свою долгосрочную работу. Как часть перезапуска B
, оригинал C
остановлен (не перезапущен) и новый C
создан (что вы называете C'
) это дитя перезапущенного B
, Первый C
не будет ребенком перезапущен B
тем не мение.
Когда первый C
заканчивается, его sender
ref все еще действителен, и этот ответ все еще может быть доставлен в этот почтовый ящик 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
}
}
}
Ваш вопрос содержит противоречие:
"Теперь давайте предположим, что перед отправкой и обработкой Cb B" "будет перезапущен B получит Cb от C, который был отправлен до перезапуска B"
Так какой это? Было cb
отправлено до перезагрузки или нет?
Если C перезапустится перед отправкой сообщения, оно будет потеряно. Если он был отправлен до перезапуска, но не обработан B, то он будет находиться в почтовом ящике B, и новый экземпляр B получит его.
По сути, я бы посоветовал вам разработать поток, который не развалится, как только одно сообщение будет потеряно. При работе с Akka вы всегда должны предполагать, что любое сообщение может быть потеряно в любое время.
Редактировать: забыл второй вопрос: если cb был отправлен до перезапуска, а B фактически получил его, отправитель будет ActorRef
указывая на новый экземпляр C. ActorRef
с и Actor
Это 2 разных объекта.