In the spring boot app, I have to call a method for a given frequency.This frequency will be read from the database. Frequent could be seconds or minutes or hours or days, etc. How do I implement this schedule for spring boot?
CodePudding user response:
for this you can use a cron with this annoation @Scheduled
Spring will schedule the annotated method to run at 10:15 AM on the 15th day of every month
@Scheduled(cron = "0 15 10 15 * ?")
public void scheduleTaskUsingCronExpression() {
long now = System.currentTimeMillis() / 1000;
System.out.println(
"schedule tasks using cron jobs - " now);
}
see this doc https://spring.io/guides/gs/scheduling-tasks/ and this https://spring.io/guides/gs/scheduling-tasks/
In Order to get the cron exp from the db : see this How to change Spring's @Scheduled fixedDelay at runtime?
CodePudding user response:
To give more other alternative solutions beside @Scheduled annotation.
You can use ScheduledExecutorService to execute task with fixed rate or fixed delay.
ScheduledExecutorService executorService = Executors
.newSingleThreadScheduledExecutor();
Then you can use below function which depend on your need:
scheduleAtFixedRate
scheduleWithFixedDelay
Example:
Future<String> resultFuture =
executorService.schedule(callableTask, 1, TimeUnit.SECONDS);
Future<String> resultFuture = service
.scheduleAtFixedRate(runnableTask, 100, 450, TimeUnit.MILLISECONDS);
service.scheduleWithFixedDelay(task, 100, 150, TimeUnit.MILLISECONDS);
Refer:
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html https://www.baeldung.com/java-executor-service-tutorial
PS: i highly recommend quartz framework also, it can schedule task with many different policies.
CodePudding user response:
You may use Task Exection and Sceduling API of Spring.
Your task to run in a scheduled mode
public class MyTask implements Runnable {
public void run(){
System.out.println("MyTask is running");
}
}
A service to be used for dynamically creation of sceduled jobs.
Inspired by this so answer.
You may add it in your library.
@Component
public class DbScheduledJobs {
private final TaskScheduler executor;
@Autowired
public DbScheduledJobs(TaskScheduler taskExecutor) {
this.executor = taskExecutor;
}
public void schedule(final Runnable task, String cronLike) {
executor.schedule(task, new CronTrigger(cronLike));
}
public void schedule(final Runnable task, LocalDateTime runOnceAt) {
executor.schedule(task, Date.from(runAt.atZone(ZoneId.systemDefault()).toInstant()));
}
public void schedulingExamples(final Runnable task) {
// Schedule a task to run once at the given date (here in 1minute)
executor.schedule(task, Date.from(LocalDateTime.now().plusMinutes(1)
.atZone(ZoneId.systemDefault()).toInstant()));
// Schedule a task that will run as soon as possible and every 1000ms
executor.scheduleAtFixedRate(task, 1000);
// Schedule a task that will first run at the given date and every 1000ms
executor.scheduleAtFixedRate(task, Date.from(LocalDateTime.now().plusMinutes(1)
.atZone(ZoneId.systemDefault()).toInstant()), 1000);
// Schedule a task that will run as soon as possible and every 1000ms after the previous completion
executor.scheduleWithFixedDelay(task, 1000);
// Schedule a task that will run as soon as possible and every 1000ms after the previous completion
executor.scheduleWithFixedDelay(task, Date.from(LocalDateTime.now().plusMinutes(1)
.atZone(ZoneId.systemDefault()).toInstant()), 1000);
// Schedule a task with the given cron expression
executor.schedule(task, new CronTrigger("*/5 * * * * MON-FRI"));
}
}
Your actual service, which reads from Db.
@Service
public class DbService {
private final DbScheduledJobs dbScheduledJobs;
@Autowired
public DbService(DbScheduledJobs dbScheduledJobs) {
this.dbScheduledJobs = dbScheduledJobs;
}
public void example() {
// Read your cron like schedule from db
String cronLikeScedule = "fetched from db"; // Ex. "*/5 * * * * MON-FRI"
// Choose your Runnable instance - either statically or using Reflection.
Runnable myRunnable = new MyTask();
// Add this task to run on a schedule basis dynamically.
this.dbScheduledJobs.schedule(myRunnable, cronLikeScedule);
}
}
Hope that it helps, this solution is not tested.