I've seen the following answer when looking for a way to handle schedule tasks in a self learning web app that I'm building. I'm using the latest version of Quartz and Tomcat 8.0.27 that is installed with Netbeans.
Simple example for Quartz 2.2 and Tomcat 7
XML-less
- This requires Servet 3.0+ (Tomcat 7+, Glassfish 3+, JBoss AS 7)
You only need two files: TestJob.java from the previous example and the following listener:
As I'm not using Maven and don't want to use XML, I have some questions related to it, as I'm getting an error on running the code starting Tomcat.
I'm trying to run the task every twelve hours, at 08:30 and 20:30
The answer says not to
To avoid conflicts, do not set the default listener in the web.xml
But unless I set the Listener in the web xml of my application it does not run the job.
<listener>
<listener-class>medsched.slisteners.MedSchedContextListener</listener-class>
</listener>
Should this be the case, or am I misunderstanding this part of the answer?
The error I get, even using the interval of the highlighted answer, relates to the fact that Tomcat sees the thread running without stopping. It reports the following
18-Nov-2017 15:46:20.347 WARNING [http-nio-8084-exec-3] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads
The web application [medsched] appears to have started a thread named [DefaultQuartzScheduler_Worker-10] but has failed to stop it.
This is very likely to create a memory leak. Stack trace of thread:
java.lang.Object.wait(Native Method)
org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:568)
Is there additional code I should be adding to prevent the error?
public class MedSchedContextListener extends QuartzInitializerListener{
private final static Logger LOG = LogManager.getLogger(MedSchedContextListener.class);
@Override
public void contextInitialized(ServletContextEvent sce) {
super.contextInitialized(sce);
ServletContext ctx = sce.getServletContext();
StdSchedulerFactory factory = (StdSchedulerFactory) ctx.getAttribute(QUARTZ_FACTORY_KEY);
try {
Scheduler scheduler = factory.getScheduler();
JobDetail jobDetail = JobBuilder.newJob(MedSchedReminder.class).build();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("simple").withSchedule(
CronScheduleBuilder.cronSchedule("0 30 8,20 1/1 * ? *")).startNow().build();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
} catch (Exception e) {
LOG.error("There was an error scheduling the job.", e);
}
}
}
Edited web.xml section which now stops the error.
<context-param>
<param-name>quartz:shutdown-on-unload</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>quartz:wait-on-shutdown</param-name>
<param-value>true</param-value>
</context-param>
<listener>
<listener-class>medsched.slisteners.MedSchedContextListener</listener-class>
</listener>
According to source code of QuartzInitializerListener
quartz was being shutdown but the waitOnShutdown
flag is set to false
, hence Tomcat didn't wait for quartz to finish before it shutdown so Tomcat decided that it had left threads running and complained.
Try to init the quartz:wait-on-shutdown
to true
in your listener configuration in addition to shutdown-on-unload
property which default to true
already (web.xml
).
<context-param>
<param-name>quartz:shutdown-on-unload</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>quartz:wait-on-shutdown</param-name>
<param-value>true</param-value>
</context-param>