Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly kill local threads owned by a webapp running on tomcat instructed to shutdown

A backend webapp is deployed on a Tomcat 6 servlet container. In the webapp, several monitoring threads are started. The problem is with shutdown.

  • How do I know that the webapp is requested to shutdown?
  • How should I handle this in my threads?

Currently my thread is implemented as below. When the servlet is instructed to shutdown (shutdown.sh) it does complete a clean shutdown and does not hang because of this thread -- Why?

class Updater extends Thread {
  volatile boolean interrupted = false;

  @Override
  public void run() {
    Integer lastUpdateLogId = CommonBeanFactory.getXXX()
                              .getLastUpdateLogRecordKey(MLConstants.SMART_DB_NAME);

    List<UpdateLog> updateLogRecords;
    while (!interrupted) {
      boolean isConfigurationUpdateRequested = false;

      try {
        TimeUnit.SECONDS.sleep(5);
      } catch (InterruptedException e) {
        setInterrupted(true);
      }

      updateLogRecords = CommonBeanFactory.getXXX()
                         .getLastFactsUpdateLogRecords(MLConstants.XXXX, lastUpdateLogId);

      for(UpdateLog updateLog : updateLogRecords) {
        if (updateLog.getTable_name().equals(MLConstants.CONFIG_RELOAD)) {
          isConfigurationUpdateRequested = true;
        }

        lastUpdateLogId = updateLog.getObjectKey();
      }

      if (isConfigurationUpdateRequested) {
        Configuration.getInstance().loadConfiguration();
      }
    }
  }

  public boolean getInterrupted() {
    return interrupted;
  }

  public void setInterrupted(boolean interrupted) {
    this.interrupted = interrupted;
  }
}
like image 815
Maxim Veksler Avatar asked Mar 17 '09 17:03

Maxim Veksler


2 Answers

I guess I can't reply to answers yet. Eddie's answer is not quite correct.

I found this question because I'm trying to figure out why my webapp doesn't shut down properly; I have threads that don't get killed when I run shutdown.*. In fact, it stops some threads but ultimately just sits there in some limbo state. My class is almost exactly like this one, actually.

Typing Ctrl+C in the foreground Tomcat window (on Windows) does stop everything, however using the init script that comes with Tomcat does not. Unfortunately, I haven't figured out why yet...

Edit: I figured it out. Most of my monitoring threads are started in a ServletContextListener, but when that context was "destroyed", the child threads weren't notified. I fixed it by simply keeping all child threads in a List and looping through, calling Thread.interrupt() on each within the contextDestroyed() method. It's almost the same as what Eddie said about the servlet destroy() method.

However, it's not correct that the JVM is summarily shut down when you run shutdown.{sh|bat}. It's more like that script sends a shutdown request to the Tomcat components. It's up to you to receive those shutdown messages and pass them along to your own objects.

like image 178
Josh Avatar answered Oct 21 '22 04:10

Josh


Servlets receive a lifecycle event when instructed to shut down. You can use this event to stop your monitoring Thread. That is, when a servlet is started, its init() method is called. When it is stopped, its destroy() method is called.

Override the destroy() method in your servlet and stop the thread there.

When you call shutdown.sh the whole JVM is shut down. Because the JVM stops, all threads (no matter what their state) are forcibly stopped if still running. It's the logical equivalent of calling System.exit(0);

like image 41
Eddie Avatar answered Oct 21 '22 03:10

Eddie