Sunday, April 27, 2014

How to setup a fixed shutdown sequence with Spring

Recently, I was faced with an interesting problem.
  • Our application server was listening to a queue
  • The queue used to receive messages from different sources
  • The requirement was very simple, when the application server is going down (this could happen because of many reasons, may be because we brought the site down, or we are deploying an updated software on to our application server) we do not want to miss any message from the queue.
To achieve this we just need to obey the following rules when the application server is going down.
  • We should stop consuming any further messages from the queue.
  • We should wait for the processing to complete for all messages that have already started processing.
  • After these two rules are satisfied we should continue with the shutdown of the application server.
To implement these rules successfully, we need a way to hook into the shutdown sequence of our application server.  Our application was using Spring and I had a feeling that Spring must have a way to do this pretty easily.

After googling for a while, I found the perfect solution for our situation.  The solution was pretty simple and extremely elegant.

How Do They Do It!

Spring framework provides a callback interface called SmartLifeCycle.  This interface has a bunch of lifecycle methods that get called when the application server is booting up or shutting down.

All we need to do is to create a class that implements this interface and register it with the Spring context.  Spring guarantees to notify this bean about various events that occur during the lifecycle of the application server.  

This interface provides methods like, start, stop, isRunning etc. please refer the JavaDocs for more details.

To implement the above rules all we did was to create a bean called ApplicationLifeCycle that implemented the SmartLifeCycle interface.  I could implement the above rules in the stop method of the bean.

However, this still kind of solved only part of the problem.  I also wanted to make sure that my bean class ApplicationLifeCycle was the first class that was notified when the shutdown was initiated.  This was the missing link.  

The SmartLifeCycle interface provides a solution to this problem as well.  This interface extends another interface called Phased.  The Phased interface exposes a method called getPhase which returns an int value.

From the documentation it was not very clear what was the purpose of this method and what should be the value returned from this method.  Turns out that, this is an extremely useful method.  Spring uses this method to determine the order in which the beans will be notified about the life cycle events.  
  • Let's say we have two beans ApplicationLifeyCycle1 and ApplicationLifeCycle2.  
  • These beans both implement the SmartLifeCycle interface.
  • ApplicationLifeyCycle1 returns a value 10 from the getPhase method
  • ApplicationLifeyCycle2 returns a value 20 from the getPhase method
  • When the application server starts, spring will invoke the ApplicationLifeCycle1 "start" callback before calling the ApplicationLifeCycle2 "start" callback method.
  • When the application server stops, spring will invoke the ApplicationLifeCycle2 "stop" callback before calling the ApplicationLifeCycle1 "stop" callback method.
At this point, we had found our missing link.  All we wanted to do was make sure that our ApplicationLifeCycle class gets notified that the server is shutting down before anyone else.  All we had to do was return a higher value from the getPhase method.  We ended up returning the highest value possible i.e. Integer.MAX_VALUE and that was it!

Once we did this, Spring guaranteed that our bean will be the first bean to be notified when the server is going down (this is exactly what we wanted), while it will be the last bean to be notified when the server is starting (which we didn't really care about).

The sample implementation of SmartLifeCycle interface looks like this
Thats all folks, until we meet again happy coding!
Have some Fun!