Reputation: 923
I am developing a cluster application based on Akka/Play where the Frontend node can get quarantined by the cluster. In such cases, I want to exit the Play application so that it can be restarted and rejoin the cluster.
I read on various places that the right way to gracefully stop a play application was to use the ApplicationLifecycle
. I am using dependency injection to get a DefaultApplicationLifecycle
object and call defaultApplicationLifecycle.stop()
whenever a ThisActorSystemQuarantinedEvent
occurs.
My problem is that the application ends up in a strange state where the app still runs and listens on the HTTP port, but almost nothing is working (all actors seem dead). It seems the Future
is never completed while I define no stopHook
in my application. Should I force to call System.exit()
at some point?
Upvotes: 2
Views: 805
Reputation: 12214
ApplicationLifecycle
is used to register hooks that are executed when your application stops. It is not supposed to be used to stop the application however. From the docs:
This is used to hook into Play lifecycle events, specifically, when Play is stopped.
...
Stop hooks are executed when the application is shutdown, in reverse from when they were registered. Due to this reverse ordering, a component can know that it is safe to use the components it depends on as long as it hasn't received a shutdown event.
What you really want is a Application
instance. From Application.stop
docs:
Stop the application. The returned future will be redeemed when all stop hooks have been run.
When Application.stop
is called, then all the hooks register in ApplicationLifecycle
are executed in "reverse from when they were registered". You can get an Application
instance using Dependency Injection too:
class SomeClass @Inject() (app: Application) {
def somethingHappensThatRequireApplicationToStop() = app.stop()
}
You are still able to receive requests because you just stopped the application, but not the Server
. Not completely sure about it, but I think you can inject it just the way you injected the app above:
import play.core.server.Server
class SomeClass @Inject() (app: Application, server: Server) {
def somethingHappensThatRequireApplicationToStop() = {
app.stop()
server.stop()
}
}
Also, since it stopping the server forces an app stop, you just need the following:
import play.core.server.Server
class SomeClass @Inject() (server: Server) {
def somethingHappensThatRequireToStop() = {
server.stop()
}
}
Upvotes: 3