Stop Scheduled Timer When Shutdown Tomcat

Stop scheduled timer when shutdown tomcat

Do not use Timer in an Java EE environment! If the task throws a runtime exception, then the whole Timer is killed and won't run anymore. You basically needs to restart the whole server to get it to run again. Also, it is sensitive to changes in the system clock.

Use ScheduledExecutorService instead. It's not sensitive to exceptions thrown in tasks nor to changes in system clock. You can shutdown it by its shutdownNow() method.

Here's an example of how the entire ServletContextListener implementation can look like (note: no registration in web.xml required thanks to the new @WebListener annotation):

@WebListener
public class BackgroundJobManager implements ServletContextListener {

private ScheduledExecutorService scheduler;

@Override
public void contextInitialized(ServletContextEvent event) {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new YourParsingJob(), 0, 5, TimeUnit.HOUR);
}

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

}

Tomcat 7 and ScheduledExecutorService.shutdown

Are you sure this error is related to your Thread pool? Judging by thread name 'Timer-0' it probably had been started by some sort of timer.

Also, you shutdownNow() should return you the list of Tasks that still await termination (see JavaDoc). You could build logic to wait more if list is not empty.

How do gracefully stop the timer task?

One way to do it would be to register a new shutdown hook thread using Runtime.addShutdownHook. It will cover regular shutdown scenarios like SIGINT received.

public static void main(String[] args) {
TimerTask task = new MyTimerTask();
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, 0, 1000);

Runtime.getRuntime().addShutdownHook(new Thread(MyTimerTask::close));
}

public static class MyTimerTask extends TimerTask {

public static void close() {
resource.close();
}

}

Since there are always situations when JVM will exit abruptly, e.g. SIGKILL which can't be handled by design, there will be no perfect way to close the resources. As advised in this answer one could use a wrapper script to look for JVM disappearing:

#!/usr/bin/env bash

java MyMain
wait
# cleanup resources if needed

How to stop the task scheduled in java.util.Timer class

Keep a reference to the timer somewhere, and use:

timer.cancel();
timer.purge();

to stop whatever it's doing. You could put this code inside the task you're performing with a static int to count the number of times you've gone around, e.g.

private static int count = 0;
public static void run() {
count++;
if (count >= 6) {
timer.cancel();
timer.purge();
return;
}

... perform task here ....

}

HTTP requests held up during Tomcat shutdown

This is hardly desirable behavior. When shutting down it should stop accepting new connections but I guess there was some technical challenges in implementing it. Moot, anyway as noted.

How we got past it is this:

  1. We have web servers in front of our tomcats. Get this in place, plan for long term if you do not, is my advice.
  2. have a way to tell the web server to drop a node (tomcat instance) from its list of round robin instances.
  3. after 3-4 minutes that tomcat node should be free (no new connections and old ones completed). We have a custom web server based on http://www.quickserver.org/ and it lets the back-end tomcats complete in process connections, though stops giving it new ones.
  4. when maintenance is up, we have another service on the agent to add the tomcat back to the web server(s) list of active servers.

In our case we had a way to tell the server to reloads their configs. Other servers seem to have same https://serverfault.com/questions/108261/how-to-make-modification-take-affect-without-restart-nginx

How to stop a running TimerTask

You need to cancel the timer by calling the following methods

timer.cancel();  // Terminates this timer, discarding any currently scheduled tasks.
timer.purge(); // Removes all cancelled tasks from this timer's task queue.

This will cancel the task, so something like this would work:

import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;
import java.awt.Toolkit;

class Alarm {

private static boolean run = true;

public static void main(String[] args) {
long delay;
Scanner scan = new Scanner(System.in);
System.out.print("Enter a delay in seconds: ");
delay = scan.nextInt()*1000;

final Timer timer = new Timer();

final TimerTask task = new TimerTask() {
@Override
public void run() {
if(run) {
Toolkit.getDefaultToolkit().beep();
} else {
timer.cancel();
timer.purge();
}
}
};

timer.schedule(task, delay);

// set run to false here to stop the timer.
run = false;
}
}


Related Topics



Leave a reply



Submit