Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I'm using Java and I want to keep a servlet continuously running in my application, but I'm not getting how to do it. My servlet has a method which gives counts of the user from a database on a daily basis as well as the total count of the users from the whole database. So I want to keep the servlet continuously running for that.

like image 552
pritsag Avatar asked Jan 14 '11 12:01

pritsag


1 Answers

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.

like image 52
BalusC Avatar answered Sep 21 '22 20:09

BalusC