Application and Server Lifecycle

Finatra establishes an ordered lifecycle when creating a or a c.t.server.TwitterServer and provides methods which can be implemented for running or starting core logic.

This is done for several reasons:

  • To ensure that flag parsing and module installation to build the object graph is done in the correct order such that the injector is properly configured before a user attempts attempts to access flags.
  • Ensure that object promotion and garbage collection is properly handled before accepting traffic to a server.
  • Expose any external interface before reporting a server is “healthy”. Otherwise a server may report it is healthy before binding to a port — which may fail. Depending on how monitoring is configured (typically done by monitoring the HTTP Admin Interface /health endpoint on some frequency) it could be some interval before the server is recognized as unhealthy when in fact it did not start properly as it could not bind to a port.

Thus you do not have access to the App or TwitterServer main method. Instead, any logic should be contained in overriding an @Lifecycle-annotated method or in the application or server callbacks.


If you override an @Lifecycle-annotated method you MUST first call super.lifecycleMethod() in your override to ensure that framework lifecycle events happen accordingly.

See the Creating an injectable App and Creating an injectable TwitterServer sections for more information.


At a high-level, the start-up lifecycle of a Finatra server looks like:



Upon graceful shutdown of an application or a server, all registered onExit, closeOnExit, and closeOnExitLast blocks are executed. See and

For a server, this includes closing the TwitterServer HTTP Admin Interface and shutting down and closing all installed modules. For extensions of the HttpServer or ThriftServer traits this also includes closing any external interfaces.


Note that the order of execution for all registered onExit and closeOnExit blocks is not guaranteed as they are executed on graceful shutdown roughly in parallel. Thus it is up to implementors to enforce any desired ordering.

For example, you have code which is reading from a queue (via a “subscriber”), transforming the data, and then publishing (via a “publisher”) to another queue. When the main application is exiting you most likely want to close the “subscriber” first to ensure that you transform and publish all available data before closing the “publisher”.

Assuming, that both objects are a c.t.util.Closable type, a simple way to close them would be:


However, the “subscriber” and the “publisher” would close roughly in parallel which could lead to data inconsistencies in your server if the “subscriber” is still reading before the “publisher” has closed.

Ordering onExit and closeOnExit functions?

Assuming, that the #close() method of both returns Future[Unit], e.g. like a c.t.util.Closable, a way of doing this could be:

onExit {

where the defaultCloseGracePeriod is the function.

In the above example we simply await on the #close() of the “subscriber” first and then the #close() of the “publisher” thus ensuring that the “subscriber” will close before the “publisher”.

However, we are not providing a timeout to the Await.result, which we should ideally do as well since we do not want to accidentally block our server shutdown if the defaultCloseGracePeriod is set to something high or infinite (e.g., Time.Top).

But if we don’t know the configured value of the defaultCloseGracePeriod this makes things complicated. We could just hardcode a value for the Await, or not use the defaultCloseGracePeriod:

onExit {
  Await.result(subscriber.close(defaultCloseGracePeriod), 5.seconds)
  Await.result(publisher.close(defaultCloseGracePeriod), 5.seconds)


onExit {
  Await.result(subscriber.close(4.seconds), 5.seconds)
  Await.result(publisher.close(4.seconds), 5.seconds)

However, this is obviously not ideal and there is an easier way. You can enforce the ordering of closing Closables by using closeOnExitLast.

A c.t.util.Closable passed to closeOnExitLast will be closed after all onExit and closeOnExit functions are executed. E.g.,


In this code the “publisher” is guaranteed be closed after the “subscriber”.


All the exit functions: onExit, closeOnExit, and closeOnExitLast use the defaultCloseGracePeriod as their close “deadline” and will raise a TimeoutException if all the exits (collected onExit, closeOnExit functions) do not close within the deadline. And if the lastExits (collected closeOnExitLast functions) do not close within the deadline.

If you have multiple c.t.util.Closable objects you want to close in parallel and one you want to close after all the others, you could do:


The “publisher” is guaranteed be closed after the closing of “subscriberA”, “subscriberB”, and “subscriberC”.

What to do if you don’t have a c.t.util.Closable?

You can simply use the onExit block to perform any shutdown logic, or you can wrap a function in a c.t.util.Closable to be passed to closeOnExit or closeOnExitLast.

For example:

onExit {
   Await.result(someFutureOperation, 2.seconds)

closeOnExit {
  Closable.make { deadline =>

closeOnExitLast {
  Closable.make { deadline =>

You can also wrap multiple functions in a Closable:

closeOnExit {
   Closable.make { deadline =>

Again the code in onExit and closeOnExit will be run in parallel and guaranteed to close before the functions in closeOnExitLast.


Multiple closeOnExitLast Closables will be closed in parallel with each other but after all onExit and closeOnExit functions have closed.


Modules provide hooks into the Lifecycle as well that allow instances being provided to the object graph to be plugged into the overall application or server lifecycle. See the Module Lifecycle section for more information.

More Information

As noted in the diagram in the Startup section the lifecycle or an application can be non-trivial – especially in the case of a TwitterServer.

For more information on how to create an injectable or a c.t.server.TwitterServer see the Creating an injectable App and Creating an injectable TwitterServer sections.