Обработка исключений Akka 2.1 (Scala)

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

У меня есть класс, который обертывает супервизор, и когда я вызываю метод в этом классе, он «просит» супервизора что-то сделать, а затем я использую Await.result(theFuture) для ожидания результата (я не могу продолжать без результата).

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

Я передал OneForOneStrategy конструктору маршрутизатора, который возвращает RESTART в случае Exception. В методе postRestart рабочего процесса я регистрирую перезапуск, чтобы проверить, действительно ли рабочий процесс перезапущен.

Когда рабочий процесс выдает исключение, он перезапускается, но исключение исчезает. Future, который является результатом запроса супервизора, содержит исключение, но это akka.pattern.AskTimeoutException, который выдается всего через 5 секунд, а не через 20 секунд, что является неявным тайм-аутом, который у меня задерживается. Исключение фактически возникает менее чем через секунду после запуска рабочего процесса.

Вопрос 1: как я могу получить исключение от рабочего процесса в коде, который вызывает мой класс-оболочку?

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

def receive = {
    case r: Request => 
        val response = ??? //throws an exception sometimes
        sender ! response
}

Что-то записывает исключение в консоль, но это не мой код. Трассировка стека:

[ERROR] [02/11/2013 21:34:20.093] [MySystem-akka.actor.default-dispatcher-9]  
[akka://MySystem/user/MySupervisor/MyRouter/$a] Something went wrong!
    at myApp.Worker.$$anonfun$receive$1.applyOrElse(Source.scala:169)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:425)
at akka.actor.ActorCell.invoke(ActorCell.scala:386)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:230)
at akka.dispatch.Mailbox.run(Mailbox.scala:212)
at akka.dispatch.ForkJoinExecutorConfigurator$MailboxExecutionTask.exec(AbstractDispatcher.scala:502)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:262)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:975)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1478)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104)

Строка 169 из Source.scala — это строка val response = ???, показанная в листинге метода receive выше.

Вопрос 2: кто регистрирует это исключение в консоли и как его остановить?


person John Smith    schedule 11.02.2013    source источник
comment
Q2: см. ActorLogging.   -  person twillouer    schedule 12.02.2013
comment
Q1: почему бы не использовать Try? (скала 2.10)   -  person twillouer    schedule 12.02.2013
comment
@twillouer Я использую Try -> myFuture.value.get дает Try, который в данном случае является сбоем, содержащим исключение тайм-аута.   -  person John Smith    schedule 12.02.2013
comment
почему бы не вернуть Try ? как отправитель! Пытаться(...) ?   -  person twillouer    schedule 12.02.2013
comment
Вы имеете в виду поймать исключение в рабочем потоке и вернуть ошибку? Если это то, что вы имеете в виду, то я надеялся, если это возможно, избежать перехвата исключений в воркерах.   -  person John Smith    schedule 12.02.2013
comment
@twillouer В разделе 5.3 руководства Akka 2.1 говорится о ведении журнала, но я не вижу ничего, что говорило бы о ведении журнала исключений по умолчанию. У вас есть еще подсказки? :-)   -  person John Smith    schedule 12.02.2013


Ответы (2)


1)

try somethingThatCanFail() catch {
    case e: Exception => sender ! Status.Failure(e); throw e
}

«Сбой сообщения» заставляет вызывающую сторону получить сообщение об ошибке, содержащее исключение. Выброс "e" вызывает вызов oneForOneStrategy, который перезапускает рабочий процесс.

2)

Сбой регистрирует сама система субъектов, и единственный способ успокоить ее — это отфильтровать вещи, создав и настроив собственный LoggingAdapter, как описано здесь http://doc.akka.io/docs/akka/2.1.0/scala/logging.html Есть тикет за изменение этого https://www.assembla.com/spaces/akka/tickets/2824 но он предназначен для Akka 2.2

Ответил https://groups.google.com/forum/#!topic/akka-user/fenCvYu3HYE

person John Smith    schedule 15.02.2013

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

  • Сначала watch ребенок
  • Затем вам будет отправлено Terminated(), когда актер умрет, со ссылкой на него.

Что-то типа:

class ParentActor extends Actor {
   // this is sample of how to watch for death of one of your children 
   val childActor = context.actorOf(Props[SomeService], "SomeService")
   val dyingChild = context.watch(context.actorOf(childActor))

   def receive = {
     case Terminated(`dyingChild`) =>
        println("dyingChild died") 
     case Terminated(terminatedActor) => 
        println(s"This child just died $terminatedActor")
   }
 }

Надеюсь это поможет.

person Steven Levine    schedule 14.02.2013
comment
Это не отвечает ни на один вопрос. - person John Smith; 15.02.2013