Background Timer Task in Jsp/Servlet Web Application

Background timer task in JSP/Servlet web application

To start, I wouldn't use JSP for this. There it is not for.

When you're on Java EE 5, use the container-provided jobscheduling APIs for this. Further detail depends on the container you're using. JBoss AS 5 for example ships with Quartz out the box. Or when you're using a framework on top of JSP/Servlet which offers jobscheduling APIs, like as Spring, then you should use it.

If there are none (e.g. you're using just Tomcat 6), or you want to be independent from the container and/or framework, create a ServletContextListener with a ScheduledExecutorService. Further detail can be found in this answer.

Or when you're already on a Java EE 6 container which supports EJB 3.1 (JBoss AS 6, GlassFish 3, but thus not Tomcat 7), easiest is to create a @Singleton EJB with @Schedule method.

@Singleton
public class UpdateSubscriptions {

@Schedule(hour="*/6", minute="0", second="0", persistent=false)
public void run() {
// Do your job here.
}

}

That's it. No further configuration is necessary.


Update: as per the comments, you're using Tomcat (6 or 7?). To start a thread during webapp's startup which runs the task every 6 hours, use the example as provided in the beforelinked answer and make the following change in the scheduleAtFixedRate() method

scheduler.scheduleAtFixedRate(new UpdateSubscriptions(), 0, 6, TimeUnit.HOURS);

The class UpdateSubscriptions must implement Runnable and the actual job needs to be done in the run() method which you @Override, like as in the example in the linked answer.

How to run a background task in a servlet based web application?

Your problem is that you misunderstand the purpose of the servlet. It's intented to act on HTTP requests, nothing more. You want just a background task which runs once on daily basis.

EJB available? Use @Schedule

If your environment happen to support EJB (i.e. a real Java EE server such as WildFly, JBoss, TomEE, Payara, GlassFish, etc), then use @Schedule instead. Here are some examples:

@Singleton
public class BackgroundJobManager {

@Schedule(hour="0", minute="0", second="0", persistent=false)
public void someDailyJob() {
// Do your job here which should run every start of day.
}

@Schedule(hour="*/1", minute="0", second="0", persistent=false)
public void someHourlyJob() {
// Do your job here which should run every hour of day.
}

@Schedule(hour="*", minute="*/15", second="0", persistent=false)
public void someQuarterlyJob() {
// Do your job here which should run every 15 minute of hour.
}

@Schedule(hour="*", minute="*", second="*/5", persistent=false)
public void someFiveSecondelyJob() {
// Do your job here which should run every 5 seconds.
}

}

Yes, that's really all. The container will automatically pickup and manage it.

EJB unavailable? Use ScheduledExecutorService

If your environment doesn't support EJB (i.e. you're not using not a real Java EE server, but a barebones servletcontainer such as Tomcat, Jetty, etc), then use ScheduledExecutorService. This can be initiated by a ServletContextListener. Here's a kickoff example:

@WebListener
public class BackgroundJobManager implements ServletContextListener {

private ScheduledExecutorService scheduler;

@Override
public void contextInitialized(ServletContextEvent event) {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 1, TimeUnit.DAYS);
scheduler.scheduleAtFixedRate(new SomeHourlyJob(), 0, 1, TimeUnit.HOURS);
scheduler.scheduleAtFixedRate(new SomeQuarterlyJob(), 0, 15, TimeUnit.MINUTES);
scheduler.scheduleAtFixedRate(new SomeFiveSecondelyJob(), 0, 5, TimeUnit.SECONDS);
}

@Override
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}

}

Where the job classes look like this:

public class SomeDailyJob implements Runnable {

@Override
public void run() {
// Do your daily job here.
}

}
public class SomeHourlyJob implements Runnable {

@Override
public void run() {
// Do your hourly job here.
}

}
public class SomeQuarterlyJob implements Runnable {

@Override
public void run() {
// Do your quarterly job here.
}

}
public class SomeFiveSecondelyJob implements Runnable {

@Override
public void run() {
// Do your quarterly job here.
}

}

Do not ever think about using java.util.Timer/java.lang.Thread in a Java EE / Servlet based environment

Last but not least, never directly use java.util.Timer and/or java.lang.Thread in Java EE. This is recipe for trouble. An elaborate explanation can be found in this JSF-related answer on the same question: Spawning threads in a JSF managed bean for scheduled tasks using a timer.

running periodic task at server side for servlet JSP MVC website

You can use ServletContextListener to execute some initialization on webapp's startup. The standard Java API way to run periodic tasks would be a combination of Timer and TimerTask. Here's a kickoff example:

public void contextInitialized(ServletContextEvent event) {
Timer timer = new Timer(true);
timer.scheduleAtFixedRate(new CleanDBTask(), 0, oneHourInMillis);
timer.scheduleAtFixedRate(new StatisticsTask(), 0, oneQuartInMillis);
}

where the both tasks can look like:

public class CleanDBTask extends TimerTask {
public void run() {
// Implement.
}
}

Using Timer is however not recommended in Java EE. If the task throws an exception, then the entire Timer thread is killed and you'd basically need to restart the whole server to get it to run again. The Timer is also sensitive to changes in system clock.

The newer and more robust java.util.concurrent way would be a combination of ScheduledExecutorService and just a Runnable. Here's a kickoff example:

private ScheduledExecutorService scheduler;

public void contextInitialized(ServletContextEvent event) {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new CleanDBTask(), 0, 1, TimeUnit.HOURS);
scheduler.scheduleAtFixedRate(new StatisticsTask(), 0, 15, TimeUnit.MINUTES);
}

public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}

How can I automatically invoke a servlet periodically at specified time intervals

To expand on the comments by JB Nizet…

The formerly accepted answer is kind of a hack. If the goal is to get some regular task to be performed as part of your web app, Java provides a crew slick technologies to make this happen.

ServletContextListener

The first is a hook defined by the Servlet spec to have code invoked when a web app is deployed and when a web app is shutting down. This hook is the ServletContextListener.

ScheduledExecutorService

The second piece is the executor service added to recent versions of Java as a more sophisticated alternative to the old Timer class. In particular you need the ScheduledExecutorService.

So when your web app start up, the ServletContextListener launches a ScheduledExecutorService. When the ServletContextListener is informed of a shutdown, it tells the executor to gracefully quit.

One trick to this: Be sure to capture all exceptions in your executor. If an exception leaks, the executor silently stops executing. This is a feature not a bug. Read the doc and study up with some googling.

Jakarta Concurrency

Some Servlet containers support Jakarta Concurrency. This specification provides for automatic management of the executor services discussed above.

Architecture of the application: request processing

Use a ServletContextListener to start a thread when the web application starts.

The thread should write the data into the ServletContext (e.g. via setAttribute()).

The ServletContextListener should terminate the thread when the application is stopped.

The Servlet should read the data from the ServletContext as it needs it.



Related Topics



Leave a reply



Submit