Home > OS >  How to schedule a task at runtime where the frequency of the scheduler is read from the database
How to schedule a task at runtime where the frequency of the scheduler is read from the database

Time:12-05

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.

  • Related