Akka actor cannot send self a PoisonPill

Viewed 337

Java/Akka here. I have the following actor:

public class MyActor extends AbstractActor {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    public MyActor() {
        super();
    }

    @Override
    public Receive createReceive() {
        return receiveBuilder()
            .match(Init.class, init -> {
                log.info("Sending myself a Poison Pill...");
                self().tell(PoisonPill.getInstance(), self());
            }).match(PoisonPill.class, poisonPill -> {
                log.info("Got the Poison Pill...");
                context().system().terminate();
            }).build();
    }
}

When it receives an Init message, I see the following log statement written:

Sending myself a Poison Pill...

But I never see:

Got the Poison Pill...

Furthermore the app just sits there and does not shut down as expected. Is there something in my use of self().tell(PoisonPill.getInstance(), self()) which prevents it from receiving the message and shutting down?

1 Answers

The log message doesn't appear because PoisonPill is an AutoReceivedMessage. An AutoReceivedMessage is a special type of message that Akka handles internally and is not meant to be pattern-matched in user code.

One way to shut down the actor system once the actor is "poisoned"/stopped is to override the actor's postStop() method:

@Override
public Receive createReceive() {
  return receiveBuilder()
    .match(Init.class, init -> {
      log.info("Sending myself a Poison Pill...");
      self().tell(PoisonPill.getInstance(), ActorRef.noSender());
    })
    .build();
}

@Override
public void postStop() {
  getContext().getSystem().terminate();
}
Related