How to schedule task daily + onStart() in Play 2.0.4?
Scheduler tasks should be placed only in Global class. Create two tasks, schedule only once first with initialDelay
= 0 milliseconds.
For the second task, you need to calculate seconds between current DateTime and next planned occurrence (ie. tomorrow at 8:00 o'clock) using common date/time classes, then set this difference as initialDelay
and also set frequency
to 24 hours.
In result, it will start at the application start and will schedule the task for execution each day at required hour.
Edit
There's complete sample, (save/edit the class: /app/Global.java
):
import akka.util.Duration;
import org.joda.time.DateTime;
import org.joda.time.Seconds;
import play.Application;
import play.GlobalSettings;
import play.Logger;
import play.libs.Akka;
import java.util.concurrent.TimeUnit;
public class Global extends GlobalSettings {
@Override
public void onStart(Application application) {
Akka.system().scheduler().scheduleOnce(
Duration.create(0, TimeUnit.MILLISECONDS),
new Runnable() {
@Override
public void run() {
Logger.info("ON START --- " + System.currentTimeMillis());
}
}
);
Akka.system().scheduler().schedule(
Duration.create(nextExecutionInSeconds(8, 0), TimeUnit.SECONDS),
Duration.create(24, TimeUnit.HOURS),
new Runnable() {
@Override
public void run() {
Logger.info("EVERY DAY AT 8:00 --- " + System.currentTimeMillis());
}
}
);
}
public static int nextExecutionInSeconds(int hour, int minute){
return Seconds.secondsBetween(
new DateTime(),
nextExecution(hour, minute)
).getSeconds();
}
public static DateTime nextExecution(int hour, int minute){
DateTime next = new DateTime()
.withHourOfDay(hour)
.withMinuteOfHour(minute)
.withSecondOfMinute(0)
.withMillisOfSecond(0);
return (next.isBeforeNow())
? next.plusHours(24)
: next;
}
}
Here is my solution which is lighter and supports cron expressions for scheduling. In this example, the scheduler will run everyday at 10:00 AM.
Following in your Global class:
private Cancellable scheduler;
@Override
public void onStart(Application application) {
super.onStart(application);
schedule();
}
@Override
public void onStop(Application application) {
//Stop the scheduler
if (scheduler != null) {
scheduler.cancel();
}
}
private void schedule() {
try {
CronExpression e = new CronExpression("0 00 10 ? * *");
Date nextValidTimeAfter = e.getNextValidTimeAfter(new Date());
FiniteDuration d = Duration.create(
nextValidTimeAfter.getTime() - System.currentTimeMillis(),
TimeUnit.MILLISECONDS);
Logger.debug("Scheduling to run at "+nextValidTimeAfter);
scheduler = Akka.system().scheduler().scheduleOnce(d, new Runnable() {
@Override
public void run() {
Logger.debug("Ruuning scheduler");
//Do your tasks here
schedule(); //Schedule for next time
}
}, Akka.system().dispatcher());
} catch (Exception e) {
Logger.error("", e);
}
}
This can be done using the Global Class, and over riding the onstart method. https://www.playframework.com/documentation/2.5.x/JavaGlobal
The code below prints the JVM stats in 10 Mins Intervals. The time duration can be configured in order to suit the need.
An abstract view of the coding is given below. Hope this help
public class Global extends GlobalSettings {
private Cancellable scheduler;
@Override
public void onStart(Application application) {
int timeDelayFromAppStartToLogFirstLogInMs = 0;
int timeGapBetweenMemoryLogsInMinutes = 10;
scheduler = Akka.system().scheduler().schedule(Duration.create(timeDelayFromAppStartToLogFirstLogInMs, TimeUnit.MILLISECONDS),
Duration.create(timeGapBetweenMemoryLogsInMinutes, TimeUnit.MINUTES),
new Runnable() {
@Override
public void run() {
System.out.println("Cron Job");
// Call a function (to print JVM stats)
}
},
Akka.system().dispatcher());
super.onStart(application);
}
@Override
public void onStop(Application app) {
scheduler.cancel();
super.onStop(app);
}
}