Akka: terminationcallbacks не получены

У меня есть система актеров, где я зарегистрировал некоторый код при завершении системы акторов. Код выглядит следующим образом -

object ChildActor {
  class Msg
}

class ChildActor extends Actor {
  val log = Logging(context.system, this)

  override def receive: Receive = {
    case a : String => log.info(s"received $a")
    case _ : Msg => throw new OutOfMemoryError("error")
  }
}

class ParentActor extends Actor {
  override val supervisorStrategy = OneForOneStrategy() {
    case _: OutOfMemoryError => {
      Stop
    }
    case _: Exception => Stop
  }
  val child = context.actorOf(Props[ChildActor], "child")
  override def receive: Receive = {
    case a: String => child ! a
    case msg : Msg => child ! msg
  }
}

object Test extends App {

  val customConf = ConfigFactory.parseString("""
  akka {
    jvm-exit-on-fatal-error = false
  }
  """)


  val actorSystem = ActorSystem("OOMException", ConfigFactory.load(customConf))

  actorSystem.registerOnTermination(println("going off"))

  val actor = actorSystem.actorOf(Props[ParentActor], "parentActor")

  actor ! new Msg

}

Странное поведение, которое я замечаю, связано с моими обратными вызовами. Когда я обычно запускаю приложение, я никогда не получаю обратный вызов для моего зарегистрированного кода.

Однако, когда я запускаю в режиме отладки и жду несколько секунд внутри метода terminate (), строка печатается .. Я не уверен, почему эти несколько секунд ожидания гарантируют, что все зарегистрированные обратные вызовы запущены, тогда как в обычном режиме выполнения этого не происходит .. Любая идея кого-нибудь ??

P.S: Я знаю, что OOM фатален, но мне просто интересно узнать о проблеме, и OOM - это всего лишь один сценарий.

Когда я беру дамп потока в конце, я вижу, что всегда присутствуют следующие два потока:

"OOMException-akka.actor.default-dispatcher-2" #12 prio=5 os_prio=0 tid=0x000000001e8dd800 nid=0x1029c waiting on condition [0x0000000020eff000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x0000000770700c90> (a akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinPool)
    at akka.dispatch.forkjoin.ForkJoinPool.scan(ForkJoinPool.java:2075)
    at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

"OOMException-scheduler-1" #11 prio=5 os_prio=0 tid=0x000000001e5d8800 nid=0xfba4 waiting on condition [0x000000001f35e000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at akka.actor.LightArrayRevolverScheduler.waitNanos(LightArrayRevolverScheduler.scala:85)
    at akka.actor.LightArrayRevolverScheduler$$anon$4.nextTick(LightArrayRevolverScheduler.scala:265)
    at akka.actor.LightArrayRevolverScheduler$$anon$4.run(LightArrayRevolverScheduler.scala:235)
    at java.lang.Thread.run(Thread.java:748)

Планировщик должен был завершить работу, поскольку система акторов завершила работу .. не знаю, почему это находится в состоянии ожидания по времени ..

0
0
127
1

Ответы 1

App может быть здесь сложным, возможно, JVM завершается (потому что все оставшиеся потоки являются потоками демона) до того, как ваш обратный вызов может быть выполнен.

Сначала я предлагаю поместить код вашего приложения в метод def main(...).

Вместо println используйте что-то вроде этого:

val promise = Promise.empty[Unit]
actorSystem.registerOnTermination(promise.success(()))
val actor = actorSystem.actorOf(Props[ParentActor], "parentActor")
actor ! new Msg
Await.ready(promise.future, Duration.INF)
println("going off")

похоже, не работает иначе, чем код, который я изначально опубликовал ..

ayush 11.04.2018 13:22

Что, если вы отключите ActorSystem обычным образом, а не из-за ошибки, возникнет ли у вас такая же проблема?

Frederic A. 11.04.2018 13:56

Другие вопросы по теме