0

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?

Masi Boo
  • 635
  • 1
  • 10
  • 24

3 Answers3

3

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.

Huy Nguyen
  • 1,931
  • 1
  • 11
  • 11
  • I have to use `Future resultFuture = executorService.schedule(callableTask, 1, TimeUnit.SECONDS);` api. Coz I have to call some other api and return result from that call. But the problem is that it can call only once for the given delay. But I have to call this for the given rate. Looks like that is only possible by the runnable. But I can't use runnable to return anything thing. – Masi Boo Dec 06 '21 at 19:59
  • Actually, you can use scheduleAtFixedRate, you just need to create Worker/Task implement Runnable, define few variables to store the final result. You can get your result when future is done. – Huy Nguyen Dec 07 '21 at 02:16
0

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?

Cheikh HAIBALA
  • 125
  • 1
  • 11
0

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.

Georgios Syngouroglou
  • 18,813
  • 9
  • 90
  • 92