Ошибка выключения планировщика Spring - PullRequest
14 голосов
/ 28 апреля 2010

Во время разработки планировщика на основе SPRING в контейнере Tomcat, я всегда получаю этот выход из системы при отмене развертывания веб-приложения или выключения сервера:

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

Как я могу это исправить?

спасибо Стивен Браун

Я добавляю этот слушатель в свое веб-приложение

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) {
    }
}

и мой web.xml

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

но ошибка все еще там.

пружинный конфиг:

<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>

Ответы [ 4 ]

5 голосов
/ 21 июля 2011

Имхо, это проблема кварцевого планировщика. Я подал ошибку https://jira.terracotta.org/jira/browse/QTZ-192. В качестве обходного пути, решение sleep (), предложенное Колином Питерсом, работает для меня. Чтобы не вызывать отключение дважды, можно также добавить сон в Spring 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 );
    }
  }
}
2 голосов
/ 05 июля 2011

Вот мое решение, так как ни одно из тех, которые я нашел в сети, не сработало. Это специально для отключения планировщика Quartz с помощью Spring & Tomcat

Мое объяснение здесь: http://forum.springsource.org/showthread.php?34672-Quartz-doesn-t-shutdown&p=370060#post370060

По сути, проблема, по-видимому, заключается в том, что у Quartz не хватает времени на чистое отключение, а аргумент waitForJobsToCompleteOnShutdown, похоже, не помогает. Итак, я реализовал пользовательский слушатель завершения работы в веб-приложении, получил ссылку на планировщик и выключил его вручную. А затем подождите 1 секунду, прежде чем продолжить.

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)
    {
    }
2 голосов
/ 28 апреля 2010

Вам нужно добавить отключающий крюк - см. Регистрация отключающего крюка в Spring 2.5 .

В вашем случае вам, вероятно, следует добавить слушатель контекста в ваше веб-приложение, которое делает это (запись web.xml для слушателя + класс реализации).

Использовать близко, это проще всего.

((YourClass)yourObject).close();
0 голосов
/ 07 марта 2013

Единственный способ обеспечить завершение потоков - это прервать их и присоединиться к ним.

Это можно сделать путем реализации org.quartz.InterruptableJob, как описано в ответе на вопрос Как предотвратить утечку памяти в кварце [?] .

...