3

I am using struts and quartz framework to schedule a job. It works fine.

But When I stop Tomcat(6.0.26), it throws out error on the console like

"The web application appears to have started a thread named[.....] but has failed to stop it. This is very likely to cause a memory leak.

Anyone knows how to handle this gracefully...

Currently my struts config.xml looks like this: <plug-in className="com.example.scheduler.SchedulerPlugin"> <set-property property="startOnLoad" value="true"/> <set-property property="startupDelay" value="0"/> </plug-in>

Tommi
  • 8,550
  • 5
  • 32
  • 51
ananth85
  • 137
  • 2
  • 12

3 Answers3

6

The best way to know for sure is to send a SIGQUIT (kill -3) program and analyze the output to see which thread is still running.

It is very likely that your job (which runs on top of one of Quartz threads) did not react to a shutdown signal and continued to work. For long-time-taking jobs, you can check jobExecutionContext.getScheduler().isShutdown() periodically or program your job to become InterruptableJob and properly respond to interruptions.

mindas
  • 26,463
  • 15
  • 97
  • 154
5

You need to call scheduler.shutdown(true) to tell Quartz to wait for any in-progress jobs to finish executing.

Also, some tomcat users have reported that they also need to pause the thread for a second or so after the shutdown call to allow the other threads cpu time to cleanup before tomcat tries to detect whether threads were left running.

See discussion here: http://forums.terracotta.org/forums/posts/list/3479.page

jhouse
  • 2,674
  • 1
  • 18
  • 17
4

This is an expansion on jhouse's answer. I can't put this code in a comment :-(.

Specifically, you need to add a ServletContextListener to your web.xml:

<listener>
    <listener-class>org.whatever.MyListener</listener-class>
</listener>

Then in the implementation, in the context contextDestroyed() method, sleep for 10 seconds (1 second wasn't enough for my app). It should look something like this:

public class MyListener implements ServletContextListener {


    public void contextInitialized(ServletContextEvent arg0) {}

    /**
     * @see ServletContextListener#contextDestroyed(ServletContextEvent)
     */
    public void contextDestroyed(ServletContextEvent arg0) {
        try {
            // This can't use logging because it's (hopefully) been shut down by now.
            System.out.println("Sleep for a bit so that we don't get any errors about Quartz threads not being shut down yet. ");
            // For more info, see here: http://stackoverflow.com/questions/2730354/spring-scheduler-shutdown-error
            Thread.sleep(10 * 1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

I had no need for calling the scheduler shutdown methods (it was clear they were already being called somewhere, maybe 'cuz I'm using Spring). All I needed to do was add the wait and then they all went away (except a FileWatchdog Log4j thread and some other MySQL thread, but those are different questions).

Ryan Shillington
  • 23,006
  • 14
  • 93
  • 108