Road to Akka: Stopping an actor

I am doing a sideproject using Akka. It is fun, it is interesting and I am learning a lot. But I ran into a small issue. I have this super cool akka system, different actors responsible for all kind of tasks. One actor has a pool of actors, breaking down a large, recurring task into smaller pieces. When each actor has finished his piece of the larger task, feedback is sent back. Cool! 

I am also kind of expecting to reuse all of the actors in the pool, so the next time this large task fires, I can use the same ‘processing’ power. But I noticed that some actors did not send feedback on some occasions. It seemed like they took forever to finish their task. How annoying!

After some research, it became clear that the problem is with a 3rd party library. The actor was stuck while processing. That is kind of bummer as this means that I cannot fix the problem directly. Hmmm 🙂 . Why not try to fix this with Akka? That does look like a great idea, doesn’t it? Maybe use a scheduler or an actor timer to send a timeout message or something like that.

Double Bummer

Well, that didn’t exactly turn out the way I wanted. As far as I know  you cannot stop an actor that is stuck. Well, at least not without stopping the entire system (and honestly, I am not sure to what extent that works). So yeah, that is double bummer :/. And when you think about it, it’s actually quite logical…

Using the stop() method

The documentation mentions the stop() method. That seemed like a reasonable idea. There are two possibilities here. The actor stops itself using the stop() method. 

@Override
  public Receive createReceive() {
    return receiveBuilder()
      .matchEquals("done", m ->
        getContext().stop(getSelf())
      )
      .build();
  }

Upon receiving a message indicating the wish to stop, the actor can then stop itself by calling the stop() method and giving it’s own reference. This seems awesome, but I forgot something very important: The actor was stuck while processing a message. This means that the next message will not be processed until the current one is done. Soooo… the “stop” indication will never be processed and the stop method will not be called. 

A parent actor can also try to stop a child actor. This would look like this: 

@Override
  public Receive createReceive() {
    return receiveBuilder()
      .matchEquals("interrupt-child", m ->
        getContext().stop(child)
      )
      .build();
  }

I got these examples from the Akka documentation. And there the documentation says: “Processing of the current message, if any, will continue before the actor is stopped, but additional messages in the mailbox will not be processed.”

So I am facing the same problem here. As the previous message will continue processing, the actor will never be stopped. 

Other ways of stopping

If you continue the documentation (don’t forget to scroll down), you can also try to use the ‘kill’ message and the ‘poison pill’ message to try and stop your actor. But again, these methods rely on messages being processed and we already figured out that this does not work if the actor you are trying to stop is stuck. 

Proven with code

I have made a small example in java, which you can find here. It consists of 2 actors, one is the supervisor and the other one I called ‘unstoppable’ because… well… because as far as I know, you can’t stop it.

The unstoppable actor logs a message every 5 seconds. The supervisor will try and stop (unsuccessfully) it using a different method every 16 seconds. I would say try it and see for yourself.