Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring update scheduler

I have a scheduled job in Spring, I get its cron from my database. Every time it is executed, the next execution time is updated. So, if it is configured to run every 10 minutes, I can change the value into the database to schedule that job every 15 minutes.

The problem is that I have to wait for the execution to get the updated cron: if a job is scheduled every 15 minutes and I want to change this value to be every 2 minutes, I have to wait for the next execution (up to 15 minutes) to have this job every 2 minutes.

Is there a way to get this job rescheduled after I update the database?

I thought to destroy and refresh this bean, but it is not working (maybe it is not possible or something was wrong in my implementation). Maybe there is a way to trigger an event to execute method configureTask.

Here the snippet of my scheduled job.

@EnableScheduling
@Component
public class MyClass implements SchedulingConfigurer {

    private static final String JOB = "My personal task";

    @Autowired
    JobRepository jobRepository;

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.addTriggerTask(new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello World!");
            }
        }, new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                JobScheduled byJobNameIgnoreCase = jobRepository.findByJobNameIgnoreCase(JOB); // read from database 
                String cron = byJobNameIgnoreCase.getCrontab();
                CronTrigger trigger = new CronTrigger(cron);
                return trigger.nextExecutionTime(triggerContext);
            }
        });
    }

}
like image 208
Daniele Bizzozero Avatar asked Dec 16 '16 14:12

Daniele Bizzozero


Video Answer


1 Answers

To manage this, I created a SchedulerOrchestrator, which manages my jobs. The jobs contain a SchedulerFuture.

Here the code that I hope can help someone else.

Let's start with an interface which will be implemented by my jobs:

public interface SchedulerObjectInterface {    
    void start();
    void stop();
}

Every job needs a ScheduledFuture to stop and needs to autowire a TaskScheduler to be scheduled. Here a sample of one job (you can create as many as you want):

@Component
public class MyFirstJob implements SchedulerObjectInterface {

    private static final Logger log = LoggerFactory.getLogger(MyFirstJob.class);

    public static final String JOB = "MyFirstJob";

    @Autowired
    JobRepository jobRepository;

    private ScheduledFuture future;

    @Autowired
    private TaskScheduler scheduler;


    @Override
    public void start() {
        future = scheduler.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(JOB + "  Hello World! " + new Date());
            }
        }, new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                String cron = cronConfig();
                System.out.println(cron);
                CronTrigger trigger = new CronTrigger(cron);
                return trigger.nextExecutionTime(triggerContext);
            }
        });

    }

    @Override
    public void stop() {
        future.cancel(false);
    }

    // retrieve cron from database
    private String cronConfig() {
        JobScheduled byJobNameIgnoreCase = jobRepository.findByJobNameIgnoreCase(JOB);
        return byJobNameIgnoreCase.getCrontab();
    }

}

Finally we can add our jobs to an orchestrator:

@Configuration
public class SchedulerOrchestrator {

    private static final Logger log = LoggerFactory.getLogger(SchedulerOrchestrator.class);

    private static Map<String, SchedulerObjectInterface> schduledJobsMap = new HashMap<>();

    @Autowired
    JobRepository jobRepository;

    @Autowired
    MyFirstJob myFirstJob;

    @Autowired
    MySecondJob mySecondJob;

    @Autowired
    TaskScheduler scheduler;

    @PostConstruct
    public void initScheduler() {
        schduledJobsMap.put(MyFirstJob.JOB, myFirstJob);
        schduledJobsMap.put(MySecondJob.JOB, mySecondJob);

        startAll();
    }

    public void restart(String job) {
        stop(job);
        start(job);
    }

    public void stop(String job) {
        schduledJobsMap.get(job).stop();
    }

    public void start(String job) {
        schduledJobsMap.get(job).start();
    }

    public void startAll() {
        for (SchedulerObjectInterface schedulerObjectInterface : schduledJobsMap.values()) {
            schedulerObjectInterface.start();
        }
    }

    @Bean
    public TaskScheduler scheduler() {
        return new ThreadPoolTaskScheduler();
    }
}
like image 145
Daniele Bizzozero Avatar answered Nov 14 '22 01:11

Daniele Bizzozero