Calling ActorRef.stop() schedules a Terminate() system message. I
changed the effect of this message by splitting the
systemInvoke.terminate() method into two parts:
- in the old place only cancel receiveTimeout and .stop() all children
plus set 'stopping' flag
- in handleChildTerminated if children are empty while stopping==true
call doTerminate(), which detaches from dispatcher and does all the
usual cleanup
- if no children were there, this happens directly from terminate()
- while 'stopping', process only ChildTerminated() and Terminate(),
ignore Terminated() and dump all the rest to app.deadLetterMailbox
- to make this less convoluted move AutoReceiveMessage handling from
Actor to ActorCell (including become/unbecome), which was all
accessing ActorContext anyway
- teach TestEventListener that DeadLetters with Terminate()/Terminated()
are not that bad
There is no retry of the .stop(), yet, but that can easily be added now
in each Actor which shuts something down: simply watch the target, if no
Terminated() is received retry. It is not 100% reliable, though, if only
the ChildTerminated() was lost, because that will not be regenerated by
the deadLetterMailbox ... need to think about that one.
All tests green on my machine.