У меня есть очень простой пример, когда у меня есть Актер (SimpleActor
), который выполняет периодическую задачу, отправляя сообщение самому себе. Сообщение запланировано в конструкторе актора. В обычном случае (т.е. без сбоев) все работает нормально.
Но что, если Актёру приходится иметь дело с ошибками. У меня есть еще один Актер (SimpleActorWithFault
). У этого актера могут быть недостатки. В этом случае я генерирую его сам, выбрасывая исключение. Когда происходит сбой (т. е. SimpleActorWithFault
выдает исключение), он автоматически перезапускается. Однако этот перезапуск портит планировщик внутри Актера, который больше не работает как исключенный. И если ошибки происходят достаточно быстро, это приводит к более неожиданному поведению.
Мой вопрос: какой предпочтительный способ обработки ошибок в таких случаях? Я знаю, что могу использовать блоки 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]))
}