Tratamento de falhas em atores Akka
Eu tenho um exemplo muito simples em que eu tenho um ator (SimpleActor
) que executam uma tarefa periódica enviando uma mensagem para si. A mensagem está agendada no construtor para o ator. No caso normal (ou seja, sem falhas) tudo funciona bem.
Mas e se o ator tiver que lidar com falhas. Eu tenho outro ator (SimpleActorWithFault
) Este ator pode ter falhas. Nesse caso, eu mesmo estou gerando um, lançando uma exceção. Quando ocorre uma falha (ou seja,SimpleActorWithFault
lança uma exceção) é reiniciado automaticamente. No entanto, essa reinicialização atrapalha o agendador dentro do Actor, que não funciona mais conforme o esperado. E se as falhas acontecem com rapidez suficiente, gera um comportamento mais inesperado.
Minha pergunta é qual é a maneira preferida de lidar com falhas nesses casos? Eu sei que posso usarTry
blocos para lidar com exceções. Mas e se eu estiver estendendo outro ator em que não posso colocar um Try na superclasse ou, em alguns casos, quando eu sou uma falha, exceto no ator.
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]))
}