Spring scheduler shutdown error

24,539

Solution 1

You need to add a shutdown hook - see Registering a shutdown hook in Spring 2.5.

In your case, you probably should add a context listener to your webapp that does this (web.xml entry for the listener + implementing class).

Use close, it's easiest.

((YourClass)yourObject).close();

Solution 2

Imho this is an issue of the quartz scheduler. I filed a bug https://jira.terracotta.org/jira/browse/QTZ-192. As a workaround the sleep() solution suggested by Colin Peters works for me. To not trigger the shutdown twice one could also add the sleep to Spring's SchedulerFactoryBean:

import org.quartz.SchedulerException;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

public class SchedulerFactoryBeanWithShutdownDelay extends SchedulerFactoryBean{

  @Override
  public void destroy() throws SchedulerException {
    super.destroy();
    // TODO: Ugly workaround for https://jira.terracotta.org/jira/browse/QTZ-192
    try {
      Thread.sleep( 1000 );
    } catch( InterruptedException e ) {
      throw new RuntimeException( e );
    }
  }
}

Solution 3

Here is my solution as none of the ones that I found online worked. This is specifically to shutdown the Quartz scheduler with Spring & Tomcat

My explanation is here: http://forum.springsource.org/showthread.php?34672-Quartz-doesn-t-shutdown&p=370060#post370060

Basically what the problem seemed to be is that Quartz doesn't have enough time to cleanly shutdown and the waitForJobsToCompleteOnShutdown argument doesn't seem to help. So I implemented a custom shutdown listener in the webapp, get a reference to the scheduler and shut it down manually. And then wait for 1 second before proceeding.

public class ShutDownHook implements ServletContextListener
{

    @Override
    public void contextDestroyed(ServletContextEvent arg0)
    {
        try
        {
            // Get a reference to the Scheduler and shut it down
            WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
            Scheduler scheduler = (Scheduler) context.getBean("quartzSchedulerFactory");
            scheduler.shutdown(true);

            // Sleep for a bit so that we don't get any errors
            Thread.sleep(1000);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    @Override
    public void contextInitialized(ServletContextEvent arg0)
    {
    }
Share:
24,539
Alex
Author by

Alex

Updated on March 08, 2020

Comments

  • Alex
    Alex over 4 years

    During development a SPRING based scheduler in a tomcat container, I always get this logoutput at undeploy webapp or shutdown server:

    Apr 28, 2010 4:21:33 PM org.apache.catalina.core.StandardService stop
    INFO: Stopping service Catalina
    Apr 28, 2010 4:21:33 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
    SEVERE: A web application appears to have started a thread named [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-1] but has failed to stop it. This is very likely to create a memory leak.
    Apr 28, 2010 4:21:33 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
    SEVERE: A web application appears to have started a thread named [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-2] but has failed to stop it. This is very likely to create a memory leak.
    Apr 28, 2010 4:21:33 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
    SEVERE: A web application appears to have started a thread named [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-3] but has failed to stop it. This is very likely to create a memory leak.
    Apr 28, 2010 4:21:33 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
    SEVERE: A web application appears to have started a thread named [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-4] but has failed to stop it. This is very likely to create a memory leak.
    Apr 28, 2010 4:21:33 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
    SEVERE: A web application appears to have started a thread named [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-5] but has failed to stop it. This is very likely to create a memory leak.
    .
    .
    .    
    SEVERE: A web application created a ThreadLocal with key of type [org.springframework.core.NamedThreadLocal] (value [Prototype beans currently in creation]) and a value of type [null] (value [null]) but failed to remove it when the web application was stopped. To prevent a memory leak, the ThreadLocal has been forcibly removed.
    Apr 28, 2010 4:21:34 PM org.apache.coyote.http11.Http11Protocol destroy
    INFO: Stopping Coyote HTTP/1.1 on http-8606
    

    How can I fix this?

    thank you stevedbrown

    I add this listener to my webapp

    public class ShutDownHook implements ServletContextListener {
        @Override
        public void contextDestroyed(ServletContextEvent arg0) {
            BeanFactory bf = (BeanFactory) ContextLoader.getCurrentWebApplicationContext();
            if (bf instanceof ConfigurableApplicationContext) {
                ((ConfigurableApplicationContext)bf).close();
            }
        }
    
        @Override
        public void contextInitialized(ServletContextEvent arg0) {
        }
    }
    

    and my web.xml

    <listener>
        <listener-class>pkg.utility.spring.ShutDownHook</listener-class>
    </listener>
    

    but the error is still there.

    spring config:

    <bean id="run" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="concurrent" value="false" />
        <property name="targetObject" ref="scheduler" />
        <property name="targetMethod" value="task" />
    </bean>
    
    <bean id="cronTrg" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail" ref="run" />
        <property name="cronExpression" value="0/5 * * * * ?" />
    </bean>
    
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" destroy-method="destroy">
        <property name="triggers">
            <list>
                <ref bean="cronTrg" />
            </list>
        </property>
    </bean>