Search code examples
scalaakkaakka-supervisionakka-actor

Is an ActorRef updated when the associated Actor is restarted by the supervisor?


If I create an logging actor like so

val logger: ActorRef =
    actorSystem.actorOf(Props(new Logger()))

and the logger restarts due to an Exception, my logger stops writing to disk.

I had been sending messages logger ! msg

Am I correct in assuming that the ActorRef did not update when the supervisor restarted my logging actor?


Solution

  • ActorRef should be properly updated by Akka to point to the new instance of an actor. The docs clearly state that:

    A reference pointing to a terminated actor does not compare equal to a reference pointing to another (re-created) actor with the same path. Note that a restart of an actor caused by a failure still means that it is the same actor incarnation, i.e. a restart is not visible for the consumer of the ActorRef.

    Also here:

    When actorOf() is called it assigns an incarnation of the actor described by the passed Props to the given path. An actor incarnation is identified by the path and a UID. A restart only swaps the Actor instance defined by the Props but the incarnation and hence the UID remains the same.

    The lifecycle of an incarnation ends when the actor is stopped. At that point the appropriate lifecycle events are called and watching actors are notified of the termination. After the incarnation is stopped, the path can be reused again by creating an actor with actorOf(). In this case the name of the new incarnation will be the same as the previous one but the UIDs will differ. ...

    An ActorRef always represents an incarnation (path and UID) not just a given path. Therefore if an actor is stopped and a new one with the same name is created an ActorRef of the old incarnation will not point to the new one.

    That's one of the main advantages of using ActorRefs, otherwise it would be much more inconvenient to work with actors.

    You need to check your supervisor strategy and make sure that the actor is actually restarted. Default strategy is:

    final val defaultStrategy: SupervisorStrategy = {
      def defaultDecider: Decider = {
        case _: ActorInitializationException ⇒ Stop
        case _: ActorKilledException         ⇒ Stop
        case _: Exception                    ⇒ Restart
      }
      OneForOneStrategy()(defaultDecider)
    }
    

    Thus if you get an Exception your actor will be restarted and ActorRef should be valid, but if you get other types of Throwable then it will be stopped and ActorRef will become invalid.