1
votes

I have the following piece of code in my Actor's (I call this Actor MasterActor) receive method:

  override def receive: Receive = {
    case StopActor(id, actorConfig) =>
      log.info(s"Stopping actor with id = $id and config $actorConfig")

      stopActor(id, powerPlantCfg).pipeTo(self)
      context.become(waitForStop(sender()))

    // Other messages... not shown here for simplicity
  }

So what I'm doing above is to stop the actor and pipe the result of that which is a Future[Continue] (where Continue is a Monix Ack type) to the Actor that contains the above Receive method. The stopActor looks like this:

  private def stopActor(id: Long, cfg: ActorConfig): Future[Ack] = async {
    await(fetchActor(id).materialize) match {
      case scala.util.Success(actorRef) =>
        log.info(s"Stopping Actor with id = $id")
        context.watch(actorRef)
        context.stop(actorRef)
        Continue
      case scala.util.Failure(fail) =>
        log.error(s"Could not fetch Actor instance for id = $id because of: $fail")
        Continue
    }
  }

I'm doing the context.watch(actorRef) and this is how my waitForStop looks like:

  private def waitForStop(source: ActorRef): Receive = {
    case Continue =>
      source ! Continue
      context.become(receive)

    case someShit =>
      log.error(s"Unexpected message $someShit received while waiting for an actor to be stopped")
  }

So I have 2 questions here:

  1. When doing context.become(waitForStop(sender())), I'm closing in on the sender(), so I assume the sender in this case is the ActorRef that contains all this above code which is the MasterActor. Am I correct?

  2. How do I know explicitly that this ActorRef that I'm trying to stop is actually stopped so that I can do a context.unwatch(actorRef) as soon as it is stopped?

Any suggestions?

1

1 Answers

2
votes

You can be notified of the stop of an Actor by watching it. You are already familiar with watch:

val kenny = context.actorOf(Props[Kenny], name = "Kenny")
context.watch(kenny)

and then you can wait for a Terminated message. Once you receive it, you can unwatch what you need.

def receive = {
    case Terminated(kenny) => println("OMG, they killed Kenny")
    case _ => println("Parent received a message")
}

So my reccomendation would be to simply watch, become waiting for terminated, and issue the stop command. But I'm unsure what you are asking exactly, so this cvould be the wrong ans Blog post example