I have a timer thread that needs to run at a particular moments of the day to do an incremental replication with a database. Right now it runs at the hour, 15 minutes past the hour, 30 minutes past the hour and 45 minutes past the hour. This is the code I have which is working ok:
public class TimerRunner implements Runnable {
private static final Semaphore lock = new Semaphore(1);
private static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
public static void initialize() {
long delay = getDelay();
executor.schedule(new TimerRunner(), delay, TimeUnit.SECONDS);
}
public static void destroy() {
executor.shutdownNow();
}
private static long getDelay() {
Calendar now = Calendar.getInstance();
long p = 15 * 60; // run at 00, 15, 30 and 45 minutes past the hour
long second = now.get(Calendar.MINUTE) * 60 + now.get(Calendar.SECOND);
return p - (second % p);
}
public static void replicate() {
if (lock.tryAcquire()) {
try {
Thread t = new Thread(new Runnable() {
public void run() {
try {
// here is where the magic happens
} finally {
lock.release();
}
}
});
t.start();
} catch (Exception e) {
lock.release();
}
} else {
throw new IllegalStateException("already running a replicator");
}
}
public void run() {
try {
TimerRunner.replicate();
} finally {
long delay = getDelay();
executor.schedule(new TimerRunner(), delay, TimeUnit.SECONDS);
}
}
}
This process is started by calling TimerRunner.initialize()
when a server starts and calling TimerRunner.destroy()
.
I have created a full replication process (as opposed to incremental) that I would like to run at a certain moment of the day, say 2:00am. How would change the above code to do this? I think that it should be very simple something like if it is now around 2:00am and it's been a long time since I did the full replication then do it now, but I can't get the if right.
Beware that sometimes the replicate process takes way longer to complete. Sometimes beyond the 15 minutes, posing a problem in running at around 2:00am.