Обработка ошибок в актерах Akka
У меня очень простой пример, где у меня есть актер (SimpleActor
) которые выполняют периодическую задачу, отправляя сообщение себе. Сообщение запланировано в конструкторе для актера. В обычном случае (т.е. без сбоев) все работает нормально.
Но что, если Актер столкнется с ошибками? У меня другой актер (SimpleActorWithFault
). У этого актера могут быть недостатки. В этом случае я сам генерирую один, генерируя исключение. Когда происходит сбой (т.е.SimpleActorWithFault
выдает исключение) он автоматически перезапускается. Однако этот перезапуск портит планировщик внутри Actor, который больше не работает как исключение. И если ошибки происходят достаточно быстро, это порождает более неожиданное поведение.
Мой вопрос: каков предпочтительный способ устранения неисправностей в таких случаях? Я знаю, что могу использоватьTry
блоки для обработки исключений. Но что, если я расширяю другого актера, где я не могу поместить Try в суперкласс, или в случае, если у меня есть исключенная ошибка, происходит в актере.
import akka.actor.{Props, ActorLogging}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import akka.actor.Actor
case object MessageA
case object MessageToSelf
class SimpleActor extends Actor with ActorLogging {
//schedule a message to self every second
context.system.scheduler.schedule(0 seconds, 1 seconds, self, MessageToSelf)
//keeps track of some internal state
var count: Int = 0
def receive: Receive = {
case MessageA => {
log.info("[SimpleActor] Got MessageA at %d".format(count))
}
case MessageToSelf => {
//update state and tell the world about its current state
count = count + 1
log.info("[SimpleActor] Got scheduled message at %d".format(count))
}
}
}
class SimpleActorWithFault extends Actor with ActorLogging {
//schedule a message to self every second
context.system.scheduler.schedule(0 seconds, 1 seconds, self, MessageToSelf)
var count: Int = 0
def receive: Receive = {
case MessageA => {
log.info("[SimpleActorWithFault] Got MessageA at %d".format(count))
}
case MessageToSelf => {
count = count + 1
log.info("[SimpleActorWithFault] Got scheduled message at %d".format(count))
//at some point generate a fault
if (count > 5) {
log.info("[SimpleActorWithFault] Going to throw an exception now %d".format(count))
throw new Exception("Excepttttttiooooooon")
}
}
}
}
object MainApp extends App {
implicit val akkaSystem = akka.actor.ActorSystem()
//Run the Actor without any faults or exceptions
akkaSystem.actorOf(Props(classOf[SimpleActor]))
//comment the above line and uncomment the following to run the actor with faults
//akkaSystem.actorOf(Props(classOf[SimpleActorWithFault]))
}