Актер, контролируемый BackoffSupervisor, теряет спрятанные сообщения после перезапуска - PullRequest
0 голосов
/ 26 декабря 2018

У меня есть актер с использованием тайника.Иногда, когда он падает, он теряет все спрятанные сообщения.Я обнаружил, что это зависит от того, какую логику наблюдения я использую.

Я написал простой пример.

Актер с тайником:

case object WrongMessage
case object TestMessage
case object InitialMessage

class TestActor extends Actor with Stash {
  override def receive: Receive = uninitializedReceive

  def uninitializedReceive: Receive = {
    case TestMessage =>
      println(s"stash test message")
      stash()

    case WrongMessage =>
      println(s"wrong message")
      throw new Throwable("wrong message")

    case InitialMessage =>
      println(s"initial message")
      context.become(initializedReceive)
      unstashAll()
  }

  def initializedReceive: Receive = {
    case TestMessage =>
      println(s"test message")
  }
}

В следующем коде:TestActor никогда получает stashed TestMessage:

object Test1 extends App {
  implicit val system: ActorSystem = ActorSystem()
  val actorRef = system.actorOf(BackoffSupervisor.props(Backoff.onFailure(
      Props[TestActor], "TestActor", 1 seconds, 1 seconds, 0
  ).withSupervisorStrategy(OneForOneStrategy()({
    case _ => SupervisorStrategy.Restart
  }))))
  actorRef ! TestMessage
  Thread.sleep(5000L)
  actorRef ! WrongMessage
  Thread.sleep(5000L)
  actorRef ! InitialMessage
}

Но этот код работает хорошо:

class SupervisionActor extends Actor {
  val testActorRef: ActorRef = context.actorOf(Props[TestActor])

  override def supervisorStrategy: SupervisorStrategy = OneForOneStrategy()({
    case _ => SupervisorStrategy.Restart
  })

  override def receive: Receive = {
    case message => testActorRef forward message
  }
}

object Test2 extends App {
  implicit val system: ActorSystem = ActorSystem()
  val actorRef = system.actorOf(Props(classOf[SupervisionActor]))
  actorRef ! TestMessage
  Thread.sleep(5000L)
  actorRef ! WrongMessage
  Thread.sleep(5000L)
  actorRef ! InitialMessage
}

Я изучил источники и обнаружил, что надзор за актерами использует LocalActorRef.restart метод, который поддерживается системной логикой диспетчера , но BackoffSupervisor просто создает нового субъекта после прекращения старого ,Есть ли способ обойти это?

1 Ответ

0 голосов
/ 28 декабря 2018

Я не уверен, что можно restart в BackoffSupervisor правильно отправлять спрятанные сообщения без особых усилий по повторной реализации.

Как вы уже указали, BackoffSupervisor делает свое делоrestart, который обходит стандартный жизненный цикл актера.Фактически, это явно указано в исходном коде BackoffOnRestartSupervisor :

Какой бы ни была окончательная Директива, мы переведем все Рестарты в наши собственные Рестарты, которые включают остановку дочернего элемента.

В случае, если вы не читали об этой сообщенной проблеме , имеется соответствующее обсуждение: проблема с Backoff.onFailure .

Backoff.onStop также предоставит требуемую функцию BackoffSupervisor, но, к сожалению, она имеет свои собственные сценарии использования и не будет вызвана исключением.

...