Configure exit code and Coordinated Shutdown per-reason overrides (#25186)
* Enable exit code configurability * Rollback first approach. Implement override * Support overriding exit-jvm and terminate-actor-sys * Simplifies code handling overrides
This commit is contained in:
parent
cab48ba699
commit
9f6fc2d6da
3 changed files with 71 additions and 30 deletions
|
|
@ -323,6 +323,18 @@ class CoordinatedShutdownSpec extends AkkaSpec(ConfigFactory.parseString(
|
|||
"c" → Phase(dependsOn = Set("a", "b"), timeout = 10.seconds, recover = false, enabled = true)))
|
||||
}
|
||||
|
||||
"default exit code to 0" in {
|
||||
lazy val conf = ConfigFactory.load().getConfig("akka.coordinated-shutdown")
|
||||
val confWithOverrides = CoordinatedShutdown.confWithOverrides(conf, None)
|
||||
confWithOverrides.getInt("exit-code") should ===(0)
|
||||
}
|
||||
|
||||
"default exit code to -1 when the Reason is ClusterDowning" in {
|
||||
lazy val conf = ConfigFactory.load().getConfig("akka.coordinated-shutdown")
|
||||
val confWithOverrides = CoordinatedShutdown.confWithOverrides(conf, Some(CoordinatedShutdown.ClusterDowningReason))
|
||||
confWithOverrides.getInt("exit-code") should ===(-1)
|
||||
}
|
||||
|
||||
// this must be the last test, since it terminates the ActorSystem
|
||||
"terminate ActorSystem" in {
|
||||
Await.result(CoordinatedShutdown(system).run(CustomReason), 10.seconds) should ===(Done)
|
||||
|
|
|
|||
|
|
@ -1056,11 +1056,28 @@ akka {
|
|||
# immediately when the last phase is reached.
|
||||
exit-jvm = off
|
||||
|
||||
# Exit status to use on System.exit(int) when 'exit-jvm' is 'on'.
|
||||
exit-code = 0
|
||||
|
||||
# Run the coordinated shutdown when the JVM process exits, e.g.
|
||||
# via kill SIGTERM signal (SIGINT ctrl-c doesn't work).
|
||||
# This property is related to `akka.jvm-shutdown-hooks` above.
|
||||
run-by-jvm-shutdown-hook = on
|
||||
|
||||
# When Coordinated Shutdown is triggered an instance of `Reason` is
|
||||
# required. That value can be used to override the default settings.
|
||||
# Only 'exit-jvm', 'exit-code' and 'terminate-actor-system' may be
|
||||
# overriden depending on the reason.
|
||||
reason-overrides {
|
||||
# Overrides are applied using the `reason.getClass.getName`. This
|
||||
# default overrides the `exit-code` when the `Reason` is a cluster
|
||||
# Downing event (identified by the object
|
||||
# "akka.actor.CoordinatedShutdown$ClusterDowningReason$").
|
||||
"akka.actor.CoordinatedShutdown$ClusterDowningReason$" {
|
||||
exit-code = -1
|
||||
}
|
||||
}
|
||||
|
||||
#//#coordinated-shutdown-phases
|
||||
# CoordinatedShutdown is enabled by default and will run the tasks that
|
||||
# are added to these phases by individual Akka modules and user logic.
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import java.util.concurrent.atomic.AtomicReference
|
|||
import java.util.function.Supplier
|
||||
import java.util.Optional
|
||||
|
||||
import akka.annotation.InternalApi
|
||||
import akka.util.OptionVal
|
||||
|
||||
object CoordinatedShutdown extends ExtensionId[CoordinatedShutdown] with ExtensionIdProvider {
|
||||
|
|
@ -171,38 +172,49 @@ object CoordinatedShutdown extends ExtensionId[CoordinatedShutdown] with Extensi
|
|||
coord
|
||||
}
|
||||
|
||||
private def initPhaseActorSystemTerminate(system: ActorSystem, conf: Config, coord: CoordinatedShutdown): Unit = {
|
||||
val terminateActorSystem = conf.getBoolean("terminate-actor-system")
|
||||
val exitJvm = conf.getBoolean("exit-jvm")
|
||||
if (terminateActorSystem || exitJvm) {
|
||||
coord.addTask(PhaseActorSystemTerminate, "terminate-system") { () ⇒
|
||||
if (exitJvm && terminateActorSystem) {
|
||||
// In case ActorSystem shutdown takes longer than the phase timeout,
|
||||
// exit the JVM forcefully anyway.
|
||||
// We must spawn a separate thread to not block current thread,
|
||||
// since that would have blocked the shutdown of the ActorSystem.
|
||||
val timeout = coord.timeout(PhaseActorSystemTerminate)
|
||||
val t = new Thread {
|
||||
override def run(): Unit = {
|
||||
if (Try(Await.ready(system.whenTerminated, timeout)).isFailure && !runningJvmHook)
|
||||
System.exit(0)
|
||||
}
|
||||
}
|
||||
t.setName("CoordinatedShutdown-exit")
|
||||
t.start()
|
||||
}
|
||||
// locate reason-specific overrides and merge with defaults.
|
||||
@InternalApi private[akka] def confWithOverrides(conf: Config, reason: Option[Reason]): Config = {
|
||||
reason.flatMap { r ⇒
|
||||
val basePath = s"""reason-overrides."${r.getClass.getName}""""
|
||||
if (conf.hasPath(basePath)) Some(conf.getConfig(basePath).withFallback(conf)) else None
|
||||
}.getOrElse(
|
||||
conf
|
||||
)
|
||||
}
|
||||
|
||||
if (terminateActorSystem) {
|
||||
system.terminate().map { _ ⇒
|
||||
if (exitJvm && !runningJvmHook) System.exit(0)
|
||||
Done
|
||||
}(ExecutionContexts.sameThreadExecutionContext)
|
||||
} else if (exitJvm) {
|
||||
System.exit(0)
|
||||
Future.successful(Done)
|
||||
} else
|
||||
Future.successful(Done)
|
||||
private def initPhaseActorSystemTerminate(system: ActorSystem, conf: Config, coord: CoordinatedShutdown): Unit = {
|
||||
coord.addTask(PhaseActorSystemTerminate, "terminate-system") { () ⇒
|
||||
val confForReason = confWithOverrides(conf, coord.shutdownReason())
|
||||
val terminateActorSystem = confForReason.getBoolean("terminate-actor-system")
|
||||
val exitJvm = confForReason.getBoolean("exit-jvm")
|
||||
val exitCode = confForReason.getInt("exit-code")
|
||||
|
||||
if (exitJvm && terminateActorSystem) {
|
||||
// In case ActorSystem shutdown takes longer than the phase timeout,
|
||||
// exit the JVM forcefully anyway.
|
||||
// We must spawn a separate thread to not block current thread,
|
||||
// since that would have blocked the shutdown of the ActorSystem.
|
||||
val timeout = coord.timeout(PhaseActorSystemTerminate)
|
||||
val t = new Thread {
|
||||
override def run(): Unit = {
|
||||
if (Try(Await.ready(system.whenTerminated, timeout)).isFailure && !runningJvmHook)
|
||||
System.exit(exitCode)
|
||||
}
|
||||
}
|
||||
t.setName("CoordinatedShutdown-exit")
|
||||
t.start()
|
||||
}
|
||||
|
||||
if (terminateActorSystem) {
|
||||
system.terminate().map { _ ⇒
|
||||
if (exitJvm && !runningJvmHook) System.exit(exitCode)
|
||||
Done
|
||||
}(ExecutionContexts.sameThreadExecutionContext)
|
||||
} else if (exitJvm) {
|
||||
System.exit(exitCode)
|
||||
Future.successful(Done)
|
||||
} else
|
||||
Future.successful(Done)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue