My program has a component - dubbed the Scheduler - that lets other components register points in time at which they want to be called back. This should work much like the Unix cron service, i. e. you tell the Scheduler "notify me at ten minutes past every full hour".
I realize there are no real callbacks in Java.
Here's my approach, is there a library which already does this stuff? Feel free to suggest improvements, too.
Register call to Scheduler passes:
a time specification containing hour, minute, second, year month, dom, dow, where each item may be unspecified, meaning "execute it every hour / minute etc." (just like crontabs)
an object containing data that will tell the calling object what to do when it is notified by the Scheduler. The Scheduler does not process this data, just stores it and passes it back upon notification.
a reference to the calling object
Upon startup, or after a new registration request, the Scheduler starts with a Calendar object of the current system time and checks if there are any entries in the database that match this point in time. If there are, they are executed and the process starts over. If there aren't, the time in the Calendar object is incremented by one second and the entreis are rechecked. This repeats until there is one entry or more that match(es). (Discrete Event Simulation)
The Scheduler will then remember that timestamp, sleep and wake every second to check if it is already there. If it happens to wake up and the time has already passed, it starts over, likewise if the time has come and the jobs have been executed.
Edit: Thanks for pointing me to Quartz. I'm looking for something much smaller, however.
Lookup Quartz
If your objects know exactly the individual points in time which they wish to be executed, then you could use a java.util.concurrent.ScheduledExecutorService. Then they simple call:
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
long timeToExecute = ... //read from DB? use CronTrigger?
long delayToExecution = timeToExecute - System.currentTimeMillis();
scheduler.schedule(aRunnable, delayToExecution, TimeUnit.MILLISECONDS);
You'd only need to use Quartz if you want the scheduler itself to handle functionality like "execute every 5 seconds", or if you want complex behaviour around missed executions, or the persistence of the execution audit trail.
You can actually trivially re-use Quartz's CronTrigger class to get a "next execution time". The class is completely standalone and does not depend on being invoked from within the Quartz "context". Once you have the next execution time as a Date or long, you can just use the Java ScheduledExecutorService as above
If your needs are simple, consider using java.util.Timer:
public class TimerDemo {
public static void main(String[] args) {
// non-daemon threads prevent termination of VM
final boolean isDaemon = false;
Timer timer = new Timer(isDaemon);
final long threeSeconds = 3 * 1000;
final long delay = 0;
timer.schedule(new HelloTask(), delay, threeSeconds);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 1);
Date oneMinuteFromNow = calendar.getTime();
timer.schedule(new KillTask(timer), oneMinuteFromNow);
}
static class HelloTask extends TimerTask {
#Override
public void run() {
System.out.println("Hello");
}
}
static class KillTask extends TimerTask {
private final Timer timer;
public KillTask(Timer timer) {
this.timer = timer;
}
#Override
public void run() {
System.out.println("Cancelling timer");
timer.cancel();
}
}
}
As has been noted, the ExecutorService of java.util.concurrent offers a richer API if you need it.
Quartz is the big and obvious powerhouse in this area, but there are some alternatives to explore.
Cron4j is a decent enough library, that is a little more lightweight than Quartz. It provides good documentation and will do what you want.
Probably more interesting is if you want to use a library that fits better with Java's concurrency libraries (particularly Executors and ScheduledExecutors) then HA-JDBC has a CronExecutorService interface, implemented by its CronThreadPoolExecutor. Now, interestingly, it has a dependency on Quartz (to provide the CronExpression class), but I find that the two together work better than just Quartz alone. If you don't want large dependencies, its easy to extract the handful of classes from Quartz and HA-JDBC that make this happen.
Since you want something much smaller (just noticed your edit), grab CronExpression from Quartz, and the two HA-JDBC classes I mentioned above. That'll do it.
I would strongly recommend cron4j (already mentioned) over Quartz, unless you absolutely need some of more advanced and complex features of Quartz. Cron4j focuses nicely on what it is supposed to do, has decent documentation, and is not a kitchen-sink solution.
Quartz scheduler is usually recommended.
Can't believe java.util.Timer was voted as the answer. Quartz is really a much better choice.
A big advantage of quartz over java.util.Timer is that with quartz the jobs can be stored in the db. As a result one jvm can schedule and another can execute. Also (obviously) the request survives across jvm restarts.
Probably more interesting is if you want to use a library that fits better with Java's concurrency libraries (particularly Executors and ScheduledExecutors) then HA-JDBC has a CronExecutorService interface, implemented by its CronThreadPoolExecutor. Now, interestingly, it has a dependency on Quartz (to provide the CronExpression class), but I find that the two together work better than just Quartz alone. If you don't want large dependencies, its easy to extract the handful of classes from Quartz and HA-JDBC that make this happen.
I just wanted to say that I tried extracting these classes, and it worked! I needed these three classes:
CronExpression (quartz)
CronThreadPoolExecutor (ha-jdbc)
DaemonThreadFactory (ha-jdbc)
And I only had to do these minor tweaks:
Removing the logger from CronThreadPoolExecutor (it was created but never used)
Moved the constant YEAR_TO_GIVEUP_SCHEDULING_AT from CronTrigger to CronExpression
I was thrilled that I didn't get stuck pull in a tangle of dependencies. Congrats to the class authors!
And it's been working like a champ.
Related
I have a requirement where I need to schedule a task (from UI) that will execute only once. After completion, I should be able to re-schedule (from UI) the same task again.
I know #Schedule won't work here as I need to execute only once. So after further searching I am able to schedule the task to execute only once at specific time using TaskScheduler with Runnable and Date and also along with #Async. However I am unable to make it reschedule.
Looks like using quartz might be possible, but I haven't gone through it yet.
Is it possible to implement my requirement with Spring Trigger. I can see only two implementation of trigger interface CronTrigger and PeriodicTrigger.
Please suggest any possible approaches.
Including initial piece of code would be helpful.
The easiest way I see would be to create a regularly scheduled "trigger" method in a Spring bean that checks a certain condition and only executes the "real" action when the condition is met (e.g. the time you entered in the UI is in the past and the job has not started yet):
#Scheduled(fixedDelay = 5000)
public void trigger() {
if(condition){
//... do the action
}
}
This requires some persistence to store the "job metadata" like the execution date and the current state of the job, but that seems "lighter" than working with threads or including quartz just for this one use case.
I don't know if it's a real question or not... But i'd like to know how some of you will approach this...
I have a Spring Boot application.
Then I have a Interruttore.class, which has, among others this field timeoutDatewhich is a Date.
In the app, various instances of this class are used. The timeoutDate field can be updated, for every single object, by various factors. I need to know when the actual date reaches the timeutDate.
In a very simple (and not optimized) way i would have created a #Scheduled task, but the delay will be too short and i don't like it, how can i do?
In a very simple (and not optimized) way i would have created a
#Scheduled task, but the delay will be too short and i don't like it,
how can i do?
Why too short ?
You can use the delay you wish.
#Scheduled(fixedDelay=50000) // 50 secs
#Scheduled(fixedDelay=1000) // 1 secs
Look at the documentation for Spring's various task scheduling APIs: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html
You have plenty of choices. I think the "not optimised" idea you might have is to schedule a repeating task which searches your beans to find the expired ones. That would indeed be inefficient for large numbers of beans.
You could simply create a scheduled task for each bean with a timeoutDate, created at the same time as that bean, and when its timeoutdate is updated (Spring AOP could help with this).
Alternatively you could keep a list of beans, sorted by timeout date. Schedule a task for the time of the earliest expiry. It reaps that bean and any others who's time is past, then schedules a new task for the time of the next expiry.
If you do this, you need to make sure that:
- it handles new objects added to the list (perhaps with an expiry date earlier than the currently scheduled cull)
- it handles the case where an object is removed for a reason other than a timeout
(Unless neither of those things can happen -- in which case don't worry about it!)
You can use Quartz or Jesque(redis). Whatever task needs to be executed, you can schedule that task at that time.
If this time value can be updated anytime, you can cancel(unschedule) the previously scheduled task(using task identifiers or keys) and reschedule it with the updated time.
I would like to schedule a periodic task which executes every X hours. I have a service which is written in Java and I was thinking of creating a long running background thread that runs forever as long as the service is up. How can I ensure that we are executing the task once every X hours? Is clock drift on my host an issue I should be worried about? I know that frequency of the clock ticks may change if the CPUs are working hard.
Edit: I was thinking of adding a bean to my spring configuration to spin up the thread which will periodically perform my task.
Java provides a java.util.Timer class that is designed to execute a task on a background thread. One of the modes of operation is "repeated execution at regular intervals". There are fixed-delay and fixed-rate execution methods that can be used, depending on your exact needs.
Java 5 added a java.util.concurrent.ScheduledThreadPoolExecutor class that is more flexible than Timer, but also offers fixed-delay and fixed-rate execution methods.
If you need such precise timing that these aren't suitable, I'm not sure that Java is an appropriate solution. You would be starting to enter the realm of a real-time system. At this point, you should likely be looking for other options.
If you are worried, write a test process and run it on the target platform. Using the feature you plan to use for the real process (like ScheduledExecutorService), schedule a task to log the host time every 24 hours. If the host doesn't use NTP to keep its clock synchronized, perhaps you could also make call to a time-keeping web service and log that too. After a few days, you should have a good sense of whether you need a method to correct for drift.
My guess is that the built-in scheduler will be accurate to less than a second per day.
Is clock drift on my host an issue I should be worried about?
Yes, clock drift can be an issue when using ScheduledThreadPoolExecutor.
CronScheduler is specifically designed to be proof against clock drift.
Example usage:
Duration syncPeriod = Duration.ofMinutes(1);
CronScheduler cron = CronScheduler.create(syncPeriod);
// If you need just precisely "once every X hours", irrespective of the
// starting time
cron.scheduleAtFixedRate(0, X, TimeUnit.HOURS, runTimeMillis -> {
// Do the task
});
// If you need "once every X hours" in terms of wall clock time,
// in some time zone:
ZoneId myTZ = ZoneId.systemDefault();
cron.scheduleAtRoundTimesInDay(Duration.ofHours(X), myTZ, runTimeMillis -> {
// Do the task
});
See Javadocs for scheduleAtRoundTimesInDay.
I have some stock market data. I want to simulate the stock market by having prices sent at intervals that can be determined from the times at which trades occur.
What would the best way be to do this.
So far I have a class with static variables and methods in which I am storing the hour, min, millseconds for the last trade time. I then use the trade time for the current trade and calculate it from the stored last trade values.
I then store as a static member variable the "interval" in milliseconds in the same class as the time variables are stored.
I use this line:
timer.schedule(new RemindTask(), TimeStore.getNextInterval());
where TimeStore.getNextInterval() retrieves the interval that was calculated.
Can you think of a better way, this doesnt seem to work, nor does it seem very elegant.
If you don't want to go as far as using Quartz then look at Java's ScheduledExecutorService.
http://java.sun.com/javase/6/docs/api/java/util/concurrent/ScheduledExecutorService.html
Use Quartz.
From the linked page:
Quartz is a full-featured, open source job scheduling system that can be integrated with, or used along side virtually any J2EE or J2SE application - from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to create simple or complex schedules for executing tens, hundreds, or even tens-of-thousands of jobs; jobs whose tasks are defined as standard Java components or EJBs. The Quartz Scheduler includes many enterprise-class features, such as JTA transactions and clustering.
Well For Your Task I have a different Solution.
You can use javax.swing.Timer instead of java.util.Timer;
and then u can call the constructor by sending the delay which u want and null for action actionListeners and then you can add and addactionListeners(this) and override actionPerformed with ur task. In javax.swing.Timer the actionListeners are notified at selected interval repeatedly
In my application i want to schedule the start of processing. In two ways first on a preset date or say like every Monday. In the case of a single date i can watch the time on a tread and start processing but when two are mixed i can't come up with a good solution.
My initial thought was when application boots up i can schedule events to calendar and check if there is job to do every min or so, that would work for both single date and every week case turns out i can not use the calendar that way.
What is a good way to solve this?
Quartz is an open-source job scheduling component written in Java, you might want to check that out.
Its features range from simple timers to full-blown CRON expressions, and it's used extensively by the JBoss AS.
Look at java.util.Timer. It allows you to schedule tasks for execution at a specified time on a background thread, and it support recurring events.