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:
@Singletonpublic 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:
@WebListenerpublic 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.
I would suggest using a library like quartz in order to run the task at regular intervals. What does the servlet really do ? It sends you a report ?
Implement two classes and call startTask()
in main
.
public void startTask(){ // Create a Runnable Runnable task = new Runnable() { public void run() { while (true) { runTask(); } } }; // Run the task in a background thread Thread backgroundThread = new Thread(task); // Terminate the running thread if the application exits backgroundThread.setDaemon(true); // Start the thread backgroundThread.start();}public void runTask(){ try { // do something... Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }}