Reputation: 29537
I'm trying to get a child actor in my Scala 2.11 app (that uses Akka) to send a PoisonPill
to the top-level actor (Master
) and shut down the entire JVM process.
I uploaded this repo so you can reproduce what I'm seeing. Just clone it and run ./gradlew run
.
But essentially we have the Driver
:
object Driver extends App {
println("Starting upp the app...")
lazy val cortex = ActorSystem("cortex")
cortex.registerOnTermination {
System.exit(0)
}
val master = cortex.actorOf(Props[Master], name = "Master")
println("About to fire a StartUp message at Master...")
master ! StartUp
println("Fired! Actor system is spinning up...")
}
and then in the Child
:
class Child extends Actor {
override def receive = {
case MakeItHappen =>
println("Child will make it happen!")
context.parent ! PoisonPill
}
}
When I run ./gradlew run
I see the following output:
./gradlew run
Starting a Gradle Daemon (subsequent builds will be faster)
:compileJava NO-SOURCE
:compileScala UP-TO-DATE
:processResources NO-SOURCE
:classes UP-TO-DATE
:run
Starting upp the app...
About to fire a StartUp message at Master...
Fired! Actor system is spinning up...
Stage Director has received a command to start up the actor system!
Child will make it happen!
<==========---> 80% EXECUTING
> :run
However the JVM process never shuts down. I would have expected the PoisonPill
to kill the Master
(as well as Child
), exit/shutdown the actor system, and then the System.exit(0)
command (which I registered upon actor system termination) to kick in and exit the JVM process.
Can anyone tell what's going on here?
Upvotes: 0
Views: 826
Reputation: 19527
You're stopping the Master
, but you're not shutting down the ActorSystem
. Even though Master
is a top-level actor (i.e., an actor created by system.actorOf
), stopping it doesn't terminate the ActorSystem
(note that Master
itself has a parent, so it's not the "highest" actor in the actor hierarchy).
The normal way to terminate a ActorSystem
is to call terminate
. If you want the entire system to shut down if the Master
stops, then you could override the Master
's postStop
hook and call context.system.terminate()
there. Calling system.terminate()
in an actor's lifecycle hook is risky, however. For example, if an exception is thrown in the actor, and the actor's supervision strategy stops it, you probably don't intend to shut down the entire system at that point. Such a design is not very resilient.
Check out this pattern for shutting down an actor system "at the right time."
Upvotes: 2