2013-06-26 7 views
6

Akka in der Dokumentation korrekt Zitat sagt:Wessen Verantwortung schafft die Kinder von Akka-Schauspielern, wenn es scheitert?

die genaue Abfolge der Ereignisse während eines Neustarts ist die folgende: die Schauspieler Suspend (was bedeutet, dass es nicht normal Nachrichten verarbeiten wird, bis wieder aufgenommen) und Suspend rekursiv alle Kinder .

Eine irreführende Zitat sagt:

wieder aufnehmen Schauspieler all seinen Untergebenen wieder aufgenommen wird, einen Schauspieler Neustart Neustart alle seine Untergebenen zur Folge hat, ähnlich einem Schauspieler beendet werden auch alle seine Untergebenen beenden

Was ich vermute, ist, dass es unsere Verantwortung ist, ein Kind in der preStart-Methode zu erstellen, weil Akkas Begriff RESTART kein Neustart ist, es sei denn, y Sie erstellen die untergeordneten Elemente rekursiv und explizit in der übergeordneten Methode preStart().

Beispiel (mit Akka 2.0 & 2.2-SNAPSHOT): egal was ich versuche, Kinder werden immer nur gestoppt, nie in diesem Testfall neu gestartet. Ich erstelle Supervisor ->First ->Second Beziehung und werfen Ausnahme in der Supervisor. Was passiert ist, dass supervisor wird neu gestartet und First & Second gestoppt.

test("restart test") { 
    val system = ActorSystem("test") 
    val supervisor = system.actorOf(Props(new Supervisor), "supervisor") 
    supervisor ! CREATE(Props(new First), "first") 
    Thread.sleep(500) 

    val first = system.actorFor("akka://test/user/supervisor/first") 
    first ! CREATE(Props(new Second), "second") 
    Thread.sleep(500) 
    supervisor ! WTF 

    Thread.sleep(20000) 
    } 

    case object WTF 
    case class CREATE(p: Props, name: String) 

    class Supervisor extends Actor { 
    override val supervisorStrategy = 
     OneForOneStrategy(maxNrOfRetries = 10) { 
     case _: IllegalStateException  => Restart 
     case _: IllegalArgumentException => Stop 
     case _: Exception     => Restart 
    } 
    override def preStart() { 
     println(s"$self starts") 
    } 
    override def postStop() { 
     println(s"$self stopped") 
    } 
    override def receive = { 
     case WTF => println("throwing exception"); throw new IllegalStateException() 
     case CREATE(p, name) => context.actorOf(p, name) 
    } 
    } 
    class First extends Actor { 
    override def preStart() { 
     println(s"$self starts") 
    } 
    override def postStop() { 
     println(s"$self stopped") 
    } 
    override def receive = { 
     case WTF => println("throwing exception"); throw new IllegalStateException() 
     case CREATE(p, name) => context.actorOf(p, name) 
    } 
    } 
    class Second extends Actor { 
    override def preStart() { 
     println(s"$self starts") 
    } 
    override def postStop() { 
     println(s"$self stopped") 
    } 
    override def receive = { 
     case WTF => println("throwing exception"); throw new IllegalStateException() 
     case CREATE => sender ! "ok" 
    } 
    } 

Schauspieler [akka: // Test/user/Supervisor # 1599926629] startet Schauspieler [akka: // Test/user/Supervisor/first # 2012011668] startet Schauspieler [akka: // Test/user/Supervisor/erste/zweite # 1750038710] startet

werfen Ausnahme Schauspieler [akka: // Test/user/Supervisor # 1599926629] gestoppt [ERROR] [2013.06.26 11: 11: 16,899] [test-akka.actor.default-dispatcher-4] [akka: // test/benutzer/supervisor] null java.lang.IllegalStateException unter com.fg.mail.smtp.Inte grationSuite $ Supervisor $$ anonfun $ erhalten $ 1.applyOrElse (IntegrationSuite.scala: 40) bei akka.actor.ActorCell.receiveMessage (ActorCell.scala: 498) um ​​ akka.actor.ActorCell.invoke (ActorCell.scala: 456) bei akka.dispatch.Mailbox.processMailbox (Mailbox.scala: 237) bei akka.dispatch.Mailbox.run (Mailbox.scala: 219) bei akka.dispatch.ForkJoinExecutorConfigurator $ AkkaForkJoinTask.exec (AbstractDispatcher.scala: 386) bei scala.concurrent.forkjoin.ForkJoinTask.doExec (ForkJoinTask.java:262) bei scala.concurrent.forkjoin.ForkJoinPool $ WorkQueue.runTask (ForkJoinPool.java:975) bei scala.concurrent.forkjoin.ForkJoinPool .runWorker (ForkJoinPool.java:1478) unter scala.concurrent.forkjoin.ForkJoinWorkerThread.run (ForkJoinWorkerThread.java: 104)

Schauspieler [akka: // Test/user/Supervisor/erste/zweite # 1750038710] gestoppt Schauspieler [akka: // Test/user/Supervisor/first # 2012011668] Schauspieler [akka gestoppt: // test/user/supervisor # 1599926629] startet

Antwort

5

Ihr Verdacht ist richtig. Wenn Sie sich die 7-stufige Beschreibung des Neustartprozesses unter http://doc.akka.io/docs/akka/snapshot/general/supervision.html genauer ansehen, sehen Sie:

2. ... defaults Kündigung Anforderungen an alle Kinder zu senden ...

und

6. senden Neustart Anforderung an alle Kinder die

nicht getötet wurden

Also, Sie müssen die preRestart Haken der Eltern entweder außer Kraft setzen Akka zu stoppen, um die Kinder zu töten, oder postRestart außer Kraft setzen alle Kinder neu zu erstellen, die nur getötet wurden .

Welche Sie wählen, hängt wirklich von der Semantik Ihrer Anwendung ab. Manchmal ist es nützlich, die gesamte Hierarchie zu beenden und mit einem leeren Blatt zu beginnen, manchmal nicht.

+0

Nun, es ist eine Schande, es gibt keine dritte Option, die Kinder implizit einfach neu starten würde ... Wenn Sie darüber nachdenken, ist die einzige sichere Möglichkeit zur Bildung Hierarchie in der PreStart() -Methode ihrer Eltern. Jeder andere Weg wäre ziemlich kompliziert zu erreichen. – lisak

+0

Die Dokumentation ist ziemlich zwiespältig, weil sie überall über "Neustart" schreiben und es bedeutet eigentlich "Aufruf" PreRestart und PostRestart Lifecycle-Methoden, aber es liegt in Ihrer Verantwortung, sich um die eigentliche "START" – lisak

+0

Nein? Wenn Sie Ihre untergeordneten Elemente im Konstruktor oder preStart erstellen, werden die untergeordneten Elemente automatisch neu erstellt, wenn das übergeordnete Element neu gestartet wird. –