I have an application which needs to be run every nth minute of an hour n can be 5 , 15 , 30 etc...
So I wrote a timer which will be called every 1 minute and I will do current time in minutes % n to check if its time to schedule.
Now problem is that once the task is scheduled at nth minute , I want the timer to pause as it will take more than one minute to complete.
I want to know , is there a way to cancel the timer when job is scheduled and reschedule when the job is done.
I tried using timer.cancel but it throws IllegalState exception.
Related
I have the following while loop:
while (keepRunning) {
if (!once) {
// Run a test method every 30th second
// Run the new calculations from the database
new CalculatorDriver().run();
// Wait in the while loop for 1 second before looping again
TimeUnit.SECONDS.sleep(1);
}
}
This while loop will loop every second through the code, but now I want to run a method called: getNewCalculations() every 30th second of a minute, so for example, the method needs to run at:
18:26:30
18:27:30
18:28:30
I already found a way to run a method every x seconds:
Timer timer = new Timer();
timer.schedule(new Task(), 60 * 1000);
But I also need to start it at a specific point. In C# someone tried this to run a script every 30th and every 0th second: https://stackoverflow.com/a/53846390/10673107.
I could just add an if where the second can't be equal to 0, but I was wondering if there was a better way to do this.
How can I run it only in the 30th second?
Set an initial delay by calculating the number of seconds to wait until the next 30th second is due to arrive. If the current moment is :10, wait 20 seconds. If the current moment is :56, wait 34 seconds.
The Duration class may help with that, along with ZonedDateTime class.
If you read the Javadoc for Timer/TimerTask you will learn those classes were supplanted years ago by the Executors framework that arrived in Java 5.
Use a ScheduledExecutorService to schedule a task to run after an initial delay specified by you. After the initial delay, specify a repeating period of one minute.
Your task will then be repeating on the 30th second mark of every minute. Know that this scheduling is approximate. The host OS, the JVM’s internal scheduler, and garbage-collection all impact when the task actually runs. So each run may vary.
Or, if you want to protect against any politician-imposed anomalies on your region’s time-keeping, schedule only a one-time scheduled task rather than repeating task. Pass to that task a reference to the ScheduledExecutorService object. The task can then schedule its own next run after running the initial-delay calculation again.
Be sure to eventually shutdown your executor service. Otherwise its backing pool of threads may continue to run indefinitely even after your app ends, like a zombie 🧟♂️.
Be aware that any exception or error bubbling up to the scheduled executor service will silently halt any further scheduling.
All of these topics have been addressed many times already on Stack Overflow. Search to learn more.
I used job scheduler for sending notification at whatever time interval lets say 4 minutes at regular interval so I used
setPeriodic(duration * 60 * 1000); //duration is 4 minutes
but its inconsistent first it sends notification after 1 minute or 2 minute then 1 minute then 4 minutes then 8 minutes also I guess it caches previous duration, its here how I implemented code:
public static void Scheduler(Context context){
ComponentName componentName = new
ComponentName(context, ClsJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(0, componentName)
.setPeriodic(duration * 60 * 1000);
JobScheduler jobScheduler = (JobScheduler)
context.getSystemService (Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(builder.build());
}
You have scheduled a job at the 4-minute interval using JobScheduler on Android L. Once scheduled as periodic, this job can run only once at any time within the interval you set (start: the time you called schedule(), end: plus 4 minutes). And it will only run again after finishing the interval that it has run, only in the new range.... this behavior will continue on until you cancel the job.
e.g: the job was scheduled for 4 minutes as periodic, and 1 minute later it was executed; This job will be run again after 3 minutes, according to the 4 minutes range. In new range, it can execute at any time within 4 min.
If you don't want this periodic behavior from JobScheduler, consider use AlarmManager service to schedule your job to trigger a notification every 4min and reschedule it after triggering the notification.
Obs.: JobScheduler uses the AlarmManager service internally, to schedule a job that need be scheduled, defining the start and end times to run this job.
Android L source code references:
To set times for scheduling a periodic job
To set times for rescheduled the periodic job
When the periodic job is scheduled using AlarmManager
This is working as designed. (and part of the "power" of the JobScheduler)
From the docs:
setPeriodic(): Specify that this job should recur with the provided interval and
flex. The job can execute at any time in a window of flex length at
the end of the period.
Why dont you user Timertask for the same?
https://developer.android.com/reference/java/util/TimerTask.html
How do I get the remaining delay time of a Task that has been scheduled?
Let's say I schedule my Task like this:
Timer.schedule(myTask, 10);
How Do I get the remaining delay time before the Task is scheduled without counting the time myself?
You have getExecuteTimeMillis which you can compare to System.currentTimeMillis.
Source
I have started timer with fixed rate. When user change system Time at that time task is executed continuously.It doesn't consider about the period time. How to manage this.
timer.scheduleAtFixedRate(task, delay, period);
Note : Now system time is current time.Period is 30 seconds. Now user change system time into after 10 mins from current time.At that time timer task not consider about the period. Within a second it execute the task 20 times.
When I use
timer.schedule(task, delay, period);
instead of
timer.scheduleAtFixedRate(task, delay, period);
task working normally. If I change system time to 10 mins past time from now task doesn't executed...
How to solve this ? :(
Have a look at this Stack Overflow answer; long story short, using scheduleAtFixedRate will queue up the tasks you have scheduled and fire them relative to the system time that the task was first queued; if anything should delay these tasks from firing, they will play 'catch up' and fire as fast as they can. So in your example of how changing the system time to +10 minutes made the event fire 20 times make since given that your period is 30 seconds (1m/2 = 30s, 10m*2 = 20 events).
Using the schedule function has similar issues, except it does not play 'catch up'; if you had a timer set to fire off every 30 seconds, then change the system time to +10 minutes only 10 seconds after the timer has started, your first event will trigger, then continue to wait the 30 second delay and fire again (unless you change the system clock again).
If you want something that is independent of system time you'll need monotonic clock values. To my knowledge the Java API does not directly contain any monotonic timers (for numerous reasons), but that doesn't stop you from implementing one yourself (albeit at the cost of possible wasted execution time in custom timer class code). Here's a Stack Overflow question regarding this, as well as a Google Group discussion post on it.
If you're really hard pressed for using a monotonic timer you could potentially use the POSIX API's and do some Java->C JNI work.
I hope that can help (at least point in a solid direction).
Is it possible to change the CronTrigger state to WAITING or to some other value which stops the job execution till next day? I can pause the trigger which will stop job execution but then I have to manual resume this trigger.
Actually, I have a CronTrigger which executes job every day between say 8:00 AM - 12:00 PM, right now it's working fine but now I would like to add an aditional check that before executing every job it will check the total number of jobs executed and pause the execution till next day if the total executed jobs limit is reached.
You'll want to create a custom TriggerListener, which keeps track of the count, can veto job execution, and reschedules jobs for the next day (e.g. updates the triggers' startTime to "00:00:00" of the next day while leaving the cron expression to the same).