Akka aktor nie kończy, jeśli wyjątek zostanie wyrzucony
Obecnie próbuję zacząć od Akki i mam dziwny problem. Mam następujący kod dla mojego aktora:
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);
}
}
I tak zaczynam swoich pracowników:
val workers = Vector.fill(nrOfWorkers)(actorOf[AkkaWorkerFT].start());
val router = Routing.loadBalancerActor(SmallestMailboxFirstIterator(workers)).start()
I tak wszystko zamykam:
futures.foreach( _.await )
router ! Broadcast(PoisonPill)
router ! PoisonPill
Teraz dzieje się tak, jeśli wysyłam wiadomości workerów z n > 0( żaden wyjątek nie jest wyrzucany), wszystko działa dobrze i aplikacja wyłącza się poprawnie. Jednak jak tylko wyślę mu pojedynczą wiadomość, która spowoduje wyjątek, aplikacja nie kończy się, ponieważ nadal działa aktor, ale nie mogę rozgryźć, skąd pochodzi.
W przypadku, gdy to pomaga, jest to stos wątku, o którym mowa:
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: wątek, który się nie kończy, nie jest żadnym z wątków roboczych, ponieważ dodałem poststop callback, każdy z nich zatrzymuje się poprawnie.
PPS: Actors.registry.shutdownAll
obejdzie problem, ale myślę, że shutdownAll powinien być używany tylko w ostateczności, prawda?
3 answers
Prawidłowym sposobem radzenia sobie z problemami wewnątrz aktorów akka nie jest rzucanie wyjątków, ale raczej ustawianie hierarchii przełożonych
" rzucanie wyjątku w kodzie współbieżnym (Załóżmy, że używamy niezwiązanych aktorów), po prostu wysadzi wątek, który obecnie / align = "left" /
Nie ma sposobu, aby dowiedzieć się, że coś poszło nie tak (oprócz sprawdzanie śladu stosu). Nic na to nie poradzisz."
Zobacz Tolerancja Przez Hierarchię Przełożonych (1.2)
* Uwaga * powyższe dotyczy starych wersji Akka (1.2) W nowszych wersjach (np. np.
class Child extends Actor {
var state = 0
def receive = {
case ex: Exception ⇒ throw ex
case x: Int ⇒ state = x
case "get" ⇒ sender ! state
}
}
I w przełożonym:
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)
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-02 16:35:07
[2]}Wyłączenie logowania, aby upewnić się, że wszystko się skończy, jak zaproponował Viktor, jest trochę dziwne. Co możesz zrobić zamiast tego to:
EventHandler.shutdown()
To całkowicie wyłącza wszystkich (loggera) słuchaczy, którzy trzymają świat za wyjątkiem:
def shutdown() {
foreachListener(_.stop())
EventHandlerDispatcher.shutdown()
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-05 19:36:25
Obrót loggera w akka.conf
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-29 20:24:37