Question
I seem to be observing a scenario in which the messages stashed for a typed supervised actor are lost during a restart, using the Akka backoff supervision strategy.
Is this expected behavior? If not, how can I implement ensure these stashed messages are retained?
The Setup
I create a typed supervised actor with a stash
BackoffSupervisorStrategy backoff = SupervisorStrategy
.restartWithBackoff(Duration.ofMillis(10), Duration.ofMillis(10000), 0)
.withStashCapacity(2000);
return Behaviors.supervise(Behaviors.setup(MyActor::new)).onFailure(Throwable.class, backoff);
It handles a command ForceFail which results in a RuntimeException so that we can let the Akka supervisor do its thing.
private Behavior<Command> forceFail(ForceFail command) {
getContext().getLog().info("Got fail command: {}", command.name);
throw new RuntimeException(command.name);
}
After spawning the actor, I send a series of tells
testSystem.tell(new ForceFail("first fail"));
testSystem.tell(new ForceFail("second fail"));
testSystem.tell(new ForceFail("third fail"));
Each tell results in an exception in the actor, triggering a restart by the supervisor.
I check the size of the StashBuffer right before the supervisor unstashes the messages during a restart.
What I see is that during the first restart, the StashBuffer shows a size of 2, as expected. However, during the second restart for the second message, the size is 0, where I would expect it to be 1.
I do not see the last message get sent to the dead letter actor. It seems to be lost, with no logging describing what happens to it.
Notes
I see in the Akka internal code, the StashBuffer unstashAll() method is called. As written in the javadocs:
If an exception is thrown by processing a message a proceeding messages and the message causing the exception have been removed from the StashBuffer, but unprocessed messages remain.
The wording seems a bit funny, but what it's saying is that it will sequentially process the messages in the stash until it processes all of them or we hit an exception. Unhandled messages remain in the stash. This does not seem to be what I'm observing though.
I'm using Akka 2.7.0.

You can embed the Actor inside a Router, so that the mailbox life-cycle is detached from the actor lifecycle, and the messages are not lost when the actor gets re-started.
This pattern will ensure that no message are lost.