In Akka Cookbook by Héctor Veiga Ortiz, the reader is told that
When an actor throws an exception, it sends a message to the supervisor, and the supervisor handles the failure by restarting that actor. It clears out the accumulated state of the actor, and creates a fresh new actor, means, it then restores the last value assigned to the state of old actor to the preRestart value.
However, I tried testing the following code, which suggests that what the author says isn't true.
import akka.actor._
import akka.actor.SupervisorStrategy._
import akka.util.Timeout
import scala.concurrent.Await
import scala.concurrent.duration._
import akka.pattern.ask
case object Error
case class StopActor(actorRef: ActorRef)
case object Inc
class LifeCycleActor extends Actor {
var sum = 1
override def preRestart(reason: Throwable, message: Option[Any]):Unit =
println(s"sum in preRestart is $sum")
override def preStart(): Unit = println(s"sum in preStart is $sum")
def receive = {
case Inc => sum += 1
case Error => throw new ArithmeticException()
case _ => println("default msg")
}
override def postStop(): Unit =
println(s"sum in postStop is ${sum * 3}")
override def postRestart(reason: Throwable): Unit = {
sum = sum * 2
println(s"sum in postRestart is $sum")
}
}
class Supervisor extends Actor {
override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute){
case _: ArithmeticException => Restart
case t =>
super.supervisorStrategy.decider.applyOrElse(t, (_:Any)=>Escalate)
}
def receive = {
case (props: Props, name: String) => sender ! context.actorOf(props, name)
case StopActor(actorRef) => context.stop(actorRef)
}
}
object ActorLifeCycle extends App {
implicit val timeout = Timeout(2 seconds)
val actorSystem = ActorSystem("Supervision")
val supervisor = actorSystem.actorOf(Props[Supervisor], "supervisor")
val childFuture = supervisor ? (Props(new LifeCycleActor), "LifeCycleActor")
val child = Await.result(childFuture.mapTo[ActorRef], 2 seconds)
child ! Inc
child ! Error
Thread.sleep(1000)
supervisor ! StopActor(child)
}
The output I get is as follows.
sbt:chpt2_ActorLifeCycle> runMain ActorLifeCycle
sum in preStart is 1
sum in preRestart is 2
[ERROR] [11/08/2018 20:06:01.423] [Supervision-akka.actor.default-dispatcher-4] [akka://Supervision/user/supervisor/LifeCycleActor] null
java.lang.ArithmeticException
sum in postRestart is 2
sum in postStop is 6
If what the author says is true, the final value should be double what it is.