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

1

11

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?

Cloven answered 11/2, 2016 at 7:10 Comment(0)
H
17

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.

Halliburton answered 11/2, 2016 at 10:42 Comment(3)
Thanks. That explains it really well. I just want to add that when an Actor is restarted, it does not finish processing the message that caused the restart. In my case, the actor never sent a message to itself to trigger the next job.Cloven
Thanks for the followup @kliew. I was curious of the reason it was not working as expected in your case.Celaeno
If you are within the Actor System you can death watch the ActorRef. But if you want to maintain an ActorRef from the outside, how would you keep this up-to-date?Eads

© 2022 - 2024 — McMap. All rights reserved.