in util-app/src/main/scala/com/twitter/app/App.scala [424:481]
final def nonExitingMain(args: Array[String]): Unit = {
observe(Register) {
App.register(this)
}
observe(LoadBindings) {
loadServiceBindings.foreach { binding => LoadService.bind(binding) }
}
observe(Init) {
for (f <- inits) f()
}
observe(ParseArgs) {
parseArgs(args)
}
observe(PreMain) {
for (f <- premains) f()
}
observe(Main) {
// Get a main() if it's defined. It's possible to define traits that only use pre/post mains.
val mainMethod =
try Some(getClass.getMethod("main"))
catch {
case _: NoSuchMethodException => None
}
// Invoke main() if it exists.
mainMethod.foreach { method =>
try method.invoke(this)
catch {
case e: InvocationTargetException => throw e.getCause
}
}
}
observe(PostMain) {
for (f <- postmains.asScala) f()
}
observe(Close) {
// We get a reference to the `close()` Future in order to Await upon it, to ensure the thread
// waits for `close()` to complete.
// Note that the Future returned here is the same as `promise` exposed via ClosableOnce,
// which is the same result that would be returned by an `Await.result` on `this`.
val closeFuture = close(defaultCloseGracePeriod)
val waitForIt = (closeDeadline + SecondChanceGrace).sinceNow
// No need to pass a timeout to Await, close(...) enforces the timeout for us.
if (!suppressGracefulShutdownErrors) Await.result(closeFuture, waitForIt)
else {
try { // even if we suppress shutdown errors, we give the resources time to close
Await.ready(closeFuture, waitForIt)
} catch {
case e: TimeoutException =>
throw e // we want TimeoutExceptions to propagate
case NonFatal(_) => ()
}
}
}
}