Ich versuche gerade mit Akka anzufangen und stehe vor einem seltsamen Problem. Ich habe den folgenden Code für meinen Schauspieler:
class AkkaWorkerFT extends Actor {
def receive = {
case Work(n, c) if n < 0 => throw new Exception("Negative number")
case Work(n, c) => self reply n.isProbablePrime(c);
}
}
Und so starte ich meine Arbeiter:
val workers = Vector.fill(nrOfWorkers)(actorOf[AkkaWorkerFT].start());
val router = Routing.loadBalancerActor(SmallestMailboxFirstIterator(workers)).start()
Und so schalte ich alles aus:
futures.foreach( _.await )
router ! Broadcast(PoisonPill)
router ! PoisonPill
Wenn ich jetzt die Worker-Nachrichten mit n> 0 sende (es wird keine Ausnahme ausgelöst), funktioniert alles einwandfrei und die Anwendung wird ordnungsgemäß heruntergefahren. Sobald ich jedoch eine einzelne Nachricht sende, die zu einer Ausnahme führt, wird die Anwendung nicht beendet, da noch ein Akteur ausgeführt wird, aber ich kann nicht herausfinden, woher sie stammt.
Falls es hilft, ist dies der Stapel des fraglichen Threads:
Thread [akka:event-driven:dispatcher:event:handler-6] (Suspended)
Unsafe.park(boolean, long) line: not available [native method]
LockSupport.park(Object) line: 158
AbstractQueuedSynchronizer$ConditionObject.await() line: 1987
LinkedBlockingQueue<E>.take() line: 399
ThreadPoolExecutor.getTask() line: 947
ThreadPoolExecutor$Worker.run() line: 907
MonitorableThread(Thread).run() line: 680
MonitorableThread.run() line: 182
PS: Der Thread, der nicht beendet wird, ist keiner der Arbeitsthreads, da ich einen PostStop-Rückruf hinzugefügt habe. Jeder von ihnen stoppt ordnungsgemäß.
PPS: Actors.registry.shutdownAll
Umgehung des Problems, aber ich denke, shutdownAll sollte nur als letztes Mittel verwendet werden, nicht wahr?
EventHandler
? (Für mich war es das.) Es klang interessant, also habe ich den Code überprüft: Für Sie scheint der Grund zu sein, dass das Auslösen einer Ausnahme dazu führtEventHandler.error
, dass aufgerufen wird (um den Stacktrace zu drucken?) .... Ich denke, Sie müssen Werfen Sie auch eine PoisonPill auf den EventHandler, um ihn herunterzufahren. Einige Akka-Experten haben möglicherweise eine bessere (schönere) Lösung.Antworten:
Der richtige Weg, um Probleme innerhalb von Akka-Akteuren zu behandeln, besteht nicht darin, eine Ausnahme auszulösen, sondern Supervisor-Hierarchien festzulegen
siehe Fehlertoleranz durch Supervisor-Hierarchien (1.2)
* Hinweis * Dies gilt für alte Versionen von Akka (1.2). In neueren Versionen (z. B. 2.2) haben Sie immer noch eine Supervisor-Hierarchie festgelegt, aber es werden Ausnahmen abgefangen, die von untergeordneten Prozessen ausgelöst werden. z.B
class Child extends Actor { var state = 0 def receive = { case ex: Exception ⇒ throw ex case x: Int ⇒ state = x case "get" ⇒ sender ! state } }
und im Supervisor:
class Supervisor extends Actor { import akka.actor.OneForOneStrategy import akka.actor.SupervisorStrategy._ import scala.concurrent.duration._ override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) { case _: ArithmeticException ⇒ Resume case _: NullPointerException ⇒ Restart case _: IllegalArgumentException ⇒ Stop case _: Exception ⇒ Escalate } def receive = { case p: Props ⇒ sender ! context.actorOf(p) } }
siehe Fehlertoleranz durch Supervisor-Hierarchien (2.2)
quelle
Das Ausschalten der Protokollierung, um sicherzustellen, dass die Dinge beendet werden, wie von Viktor vorgeschlagen, ist etwas seltsam. Was Sie stattdessen tun können, ist:
EventHandler.shutdown()
Dadurch werden alle (Logger-) Listener sauber heruntergefahren, die die Welt nach der Ausnahme am Laufen halten:
def shutdown() { foreachListener(_.stop()) EventHandlerDispatcher.shutdown() }
quelle
Schalten Sie den Logger in der
akka.conf
quelle