3

I'm trying to get an actor Worker to not restart its child actor SubWorker when it's restarted by it's own supervisor Mngr. I've been unsuccessful even after overriding the preRestart() and postRestart in Worker. The logs still show that SubWorker is till being restarted. I'm new to Akka and Actor model, I don't know what I'm doing wrong.

case class Start()
case class ThrowExp()

class Mngr extends Actor {

  val log = Logging(context.system, this)

  override def preStart(): Unit = {
    self ! Start
  }

  def receive: Receive = {

    case Start =>
      context.actorOf(Props[Worker], "myWorker")

    case "walker_throw_exp" =>
      context.child("myWorker").get ! ThrowExp
  }
}

class Worker extends Actor {


  val log = Logging(context.system, this)

  override def preStart(): Unit = {
    self ! Start
  }


  override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
    postStop()
  }


  override def postRestart(reason: Throwable): Unit = { }

  def receive: Receive = {

    case Start =>
      // create sub worker
      context.actorOf(Props[SubWorker], "mySubWorker")


    case ThrowExp => throw new Exception("Some exception")

  }
}

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

  def receive: Receive = {
    case _ => log.info("I'm a sub worker")
  }
}

val system = ActorSystem("MySystem")
import system.dispatcher

val manager = system.actorOf(Props[Mngr], "Manager")
system.scheduler.scheduleOnce(2.seconds, manager, "walker_throw_exp")

The log

[DEBUG] [12/11/2013 20:22:04.409] [main] [EventStream(akka://MySystem)] logger log1-Logging$DefaultLogger started
[DEBUG] [12/11/2013 20:22:04.411] [main] [EventStream(akka://MySystem)] Default Loggers started
[DEBUG] [12/11/2013 20:22:04.417] [MySystem-akka.actor.default-dispatcher-4] [akka://MySystem/system] now supervising Actor[akka://MySystem/system/deadLetterListener#-1362953699]
[DEBUG] [12/11/2013 20:22:04.419] [MySystem-akka.actor.default-dispatcher-2] [akka://MySystem/system/deadLetterListener] started (akka.event.DeadLetterListener@250f4a60)
[DEBUG] [12/11/2013 20:22:04.427] [MySystem-akka.actor.default-dispatcher-3] [akka://MySystem/user] now supervising Actor[akka://MySystem/user/Manager#-684317580]
[DEBUG] [12/11/2013 20:22:04.429] [MySystem-akka.actor.default-dispatcher-2] [akka://MySystem/user/Manager] started (com.gangfly.gangbot.Mngr@34b0e482)
[DEBUG] [12/11/2013 20:22:04.431] [MySystem-akka.actor.default-dispatcher-2] [akka://MySystem/user/Manager] now supervising Actor[akka://MySystem/user/Manager/myWorker#429127943]
[DEBUG] [12/11/2013 20:22:04.432] [MySystem-akka.actor.default-dispatcher-4] [akka://MySystem/user/Manager/myWorker] started (com.gangfly.gangbot.Worker@7b70a0d3)
[DEBUG] [12/11/2013 20:22:04.434] [MySystem-akka.actor.default-dispatcher-4] [akka://MySystem/user/Manager/myWorker] now supervising Actor[akka://MySystem/user/Manager/myWorker/mySubWorker#2129589969]
[DEBUG] [12/11/2013 20:22:04.435] [MySystem-akka.actor.default-dispatcher-2] [akka://MySystem/user/Manager/myWorker/mySubWorker] started (com.gangfly.gangbot.SubWorker@3c2a5fb9)
[ERROR] [12/11/2013 20:22:06.465] [MySystem-akka.actor.default-dispatcher-2] [akka://MySystem/user/Manager/myWorker] Some exception
java.lang.Exception: Some exception
    at com.gangfly.gangbot.Worker$$anonfun$receive$2.applyOrElse(Main.scala:57)
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:498)
    at akka.actor.ActorCell.invoke(ActorCell.scala:456)
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:237)
    at akka.dispatch.Mailbox.run(Mailbox.scala:219)
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386)
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

[DEBUG] [12/11/2013 20:22:06.465] [MySystem-akka.actor.default-dispatcher-2] [akka://MySystem/user/Manager/myWorker] restarting
[DEBUG] [12/11/2013 20:22:06.469] [MySystem-akka.actor.default-dispatcher-2] [akka://MySystem/user/Manager/myWorker] restarted
[DEBUG] [12/11/2013 20:22:06.470] [MySystem-akka.actor.default-dispatcher-3] [akka://MySystem/user/Manager/myWorker/mySubWorker] restarting
[DEBUG] [12/11/2013 20:22:06.471] [MySystem-akka.actor.default-dispatcher-3] [akka://MySystem/user/Manager/myWorker/mySubWorker] restarted
Eugene Loy
  • 12,224
  • 8
  • 53
  • 79
Kennedy
  • 2,146
  • 6
  • 31
  • 44

1 Answers1

4

An Actor is restarted because its internal state has become invalid and cannot be trusted anymore. Since the child actors it creates are part of an actor’s state, they also need to be cleared out—either by stopping and re-creating (which is the default) or by being restarted in turn. This cannot be avoided. If you have an actor A which should survive some other actor B, then A cannot be a child of B. So in this case you will need to restructure your supervision hierarchy.

Roland Kuhn
  • 15,412
  • 2
  • 36
  • 45
  • Thanks for your answer. In what situation can the preRestart and postRestart methods be used in. I thought I could just override the restarting actor's lifecycle methods, preventing it from restarting actors under it. – Kennedy Dec 12 '13 at 17:15
  • No, with these hooks an actor can react to the fact that it is being restarted, for example by closing and re-opening a database connection. The semantics of restarting an actor are defined by the model; the simplest would be if you enroll to the Coursera course on [Reactive Programming](https://www.coursera.org/course/reactive) and look specifically at week 6. – Roland Kuhn Dec 12 '13 at 20:35