Акка автоматически копирует переменные, когда актер терпит неудачу - PullRequest
0 голосов
/ 09 ноября 2018

In Akka Cookbook от Эктора Вейги Ортиса, читателю говорят, что

Когда субъект выдает исключение, он отправляет сообщение супервизору, и супервизор обрабатывает сбой, перезапуская этого субъекта. Он очищает накопленное состояние субъекта и создает новый новый субъект, то есть восстанавливает последнее значение, назначенное состоянию старого субъекта, до значения preRestart.

Однако я попытался протестировать следующий код, который предполагает, что то, что говорит автор, не соответствует действительности.

import akka.actor._
import akka.actor.SupervisorStrategy._
import akka.util.Timeout
import scala.concurrent.Await
import scala.concurrent.duration._
import akka.pattern.ask

case object Error
case class StopActor(actorRef: ActorRef)
case object Inc

class LifeCycleActor extends Actor {
  var sum = 1
  override def preRestart(reason: Throwable, message: Option[Any]):Unit =
    println(s"sum in preRestart is $sum")
  override def preStart(): Unit = println(s"sum in preStart is $sum")
  def receive = {
    case Inc => sum += 1
    case Error => throw new ArithmeticException()
    case _ => println("default msg")
  }
  override def postStop(): Unit =
    println(s"sum in postStop is ${sum * 3}")
  override def postRestart(reason: Throwable): Unit = {
    sum = sum * 2
    println(s"sum in postRestart is $sum")
  }
}

class Supervisor extends Actor {
  override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute){
    case _: ArithmeticException => Restart
    case t =>
      super.supervisorStrategy.decider.applyOrElse(t, (_:Any)=>Escalate)
  }
  def receive = {
    case (props: Props, name: String) => sender ! context.actorOf(props, name)
    case StopActor(actorRef) => context.stop(actorRef)
  }
}

object ActorLifeCycle extends App {
  implicit val timeout = Timeout(2 seconds)
  val actorSystem = ActorSystem("Supervision")
  val supervisor = actorSystem.actorOf(Props[Supervisor], "supervisor")
  val childFuture = supervisor ? (Props(new LifeCycleActor), "LifeCycleActor")
  val child = Await.result(childFuture.mapTo[ActorRef], 2 seconds)
  child ! Inc
  child ! Error
  Thread.sleep(1000)
  supervisor ! StopActor(child)
}

Вывод, который я получаю, следующий:

sbt: chpt2_ActorLifeCycle> runMain ActorLifeCycle
сумма в preStart составляет 1
сумма в preRestart составляет 2
[ОШИБКА] [08.11.2008 20: 06: 01.423] [Контроль-akka.actor.default-диспетчерская-4] [akka: // Наблюдение / пользователь / супервизор / LifeCycleActor] null
java.lang.ArithmeticException
сумма в postRestart составляет 2
сумма в postStop составляет 6

Если то, что автор говорит, правда, окончательное значение должно быть в два раза больше, чем оно есть.

1 Ответ

0 голосов
/ 09 ноября 2018

Сначала я предполагаю, что вы забыли добавить sum += 1 при получении сообщения Inc в дочернем актере при публикации вопроса, пожалуйста, измените. В противном случае, когда я проверяю, вы не можете получить свой вывод.

Далее объясните ваш код:

На следующей диаграмме видно, что preReStart вызывается для старого экземпляра, а не для нового экземпляра.

enter image description here

Здесь также есть описание, подробности здесь

  1. Старый субъект получает информацию о вызове preRestart с исключением, которое вызвало перезапуск, и сообщением, которое вызвало это исключение; последний может быть Нет, если перезапуск не был вызван обработкой сообщения, например когда супервизор не перехватывает исключение и по очереди перезапускается его супервизором, или если актер перезапускается из-за сбоя одного из братьев и сестер. Если сообщение доступно, то отправитель этого сообщения также доступен обычным способом (то есть путем вызова отправителя). Этот метод является лучшим местом для очистки, подготовки передачи к свежему экземпляру субъекта и т. Д. По умолчанию он останавливает все дочерние элементы и вызывает postStop.
  2. Исходная фабрика из вызова actorOf используется для создания нового экземпляра.
  3. Новый метод postRestart нового актера вызывается с исключением, которое вызвало перезапуск. По умолчанию предварительный запуск вызывается, как и при обычном запуске.

Итак, для вашего примера:

  • при вызове preRestart выводится сумма старого актера, то есть 2, обратите внимание: у вас есть inc.
  • при вызове postRestart выводится сумма нового актера, то есть начальное значение 1 с вычислением sum = sum * 2, в конце выдается 2, а не 4. Inc message просто получает на старом экземпляре, а не на новом.

Наконец, содержание книги:

Когда субъект выдает исключение, он отправляет сообщение супервизору, и супервизор обрабатывает сбой, перезапуская этого субъекта. Он очищает накопленное состояние субъекта и создает новый новый субъект, то есть восстанавливает последнее значение, назначенное состоянию старого субъекта, до значения preRestart.

Я думаю, что вы обеспокоены it then restores the last value assigned to the state of old actor to the preRestart value. Я не совсем знаю, что это значит, если вы просто думаете, что оно присваивает последнее значение старого актора функции preRestart, тогда это правильно, так как он просто запускается на старом экземпляре, в противном случае, это кажется конфликтующим с официальным руководством akka & эксперимент; И, если хотите восстановить значение, нам, возможно, пришлось использовать resume, а не restart. В любом случае, я думаю, что мы должны использовать официальный документ akka в качестве стандарта и понимать правильную логику.

...