10

In spring boot, can I schedule a spring job by not using @Scheduled annotation to a method?

I am working with spring job in the spring boot. I want to schedule a job by using cron expression, but without using @Scheduled(cron = " ") annotation to the method.

I know that I can schedule a job inside this method as below.

@Scheduled (cron = "0 10 10 10 * ?")

public void execute() { 

   / * some job code * /

}

But I want it to be dynamic so that I can take a cron expression as input from the user and schedule it.

Romil Patel
  • 12,879
  • 7
  • 47
  • 76
Aram1289
  • 115
  • 1
  • 1
  • 6
  • Possible duplicate of [Spring boot add new schedule job dynamically](https://stackoverflow.com/questions/46974272/spring-boot-add-new-schedule-job-dynamically) – Jason Aller Jul 08 '19 at 17:20

3 Answers3

7

I came up with a working example since I found your question interesting and have been interested in this problem before. It's based entirely on the source code so I have no idea if it comes close to following best practice. Nonetheless, you may be able to tune it to your needs. FYI, you don't necessarily need to create a new ScheduledTaskRegistrar object - I figured that since your objective is a dynamic scheduler, you wouldn't be interested in defining your tasks purely in the overwritten method.

@SpringBootApplication
public class TaskScheduler implements SchedulingConfigurer, CommandLineRunner {

    public static void main(String[] args){SpringApplication.run(TaskScheduler.class, args);}

    List<CronTask> cronTasks;

    @Override
    public void run(String... args) throws Exception {
        CronTask task = this.createCronTask(new Runnable() {
            @Override
            public void run() {
                System.out.println(LocalDateTime.now());
            }
        }, "1/10 * * * * *");

        ScheduledTaskRegistrar taskRegistrar = new ScheduledTaskRegistrar();
        taskRegistrar.addCronTask(task);
        configureTasks(taskRegistrar);
        Thread.sleep(51);

        taskRegistrar.destroy();
        taskRegistrar = null;

        ScheduledTaskRegistrar taskRegistrar2 = new ScheduledTaskRegistrar();
        taskRegistrar2.addCronTask(task);
        configureTasks(taskRegistrar2);

    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        // "Calls scheduleTasks() at bean construction time" - docs
        taskRegistrar.afterPropertiesSet();
    }

    public CronTask createCronTask(Runnable action, String expression) {
        return new CronTask(action, new CronTrigger(expression));
    }

}

I have experience using cron jobs in Azure and other places. Programming in Java, I have typically used @Scheduled with fixed times just for the sake of simplicity. Hope this is useful to you though.

Christian Meyer
  • 605
  • 8
  • 15
0

Here is my working example for these who wants to use TaskScheduler without using the @Scheduled annotation.

@Configuration class

@Configuration
public class SchedulerConfig implements SchedulingConfigurer {

    final Logger LOGGER = LogManager.getLogger(SchedulerConfig.class);

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        LOGGER.debug("Creating Async Task Scheduler");
        scheduledTaskRegistrar.setTaskScheduler(taskScheduler());
    }

    // This is mandatory otherwise it will to be able to find bean of       
    // taskScheduler. Without this it was giving runtime error says, can not find 
    // taskScheduler bean.
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(20); // Better to read it from property file.
        scheduler.setThreadNamePrefix("ThreadScheduler-");
        scheduler.initialize();
        return scheduler;
    }
}

Scheduler Class which is called from Application class.


@Component
public class MyTaskScheduler {

    private TaskScheduler taskScheduler;
    // Here we are auto-wiring taskScheduler, that's why need to create 
   // taskScheduler bean in configuration class
    @Autowired
    public void setScheduler(TaskScheduler scheduler) {
        this.taskScheduler = scheduler;
    }

    public void schedule() {
        taskScheduler.scheduleWithFixedDelay(new Runnable(){
            @Override
            public void run() {
                System.out.println("I am running after every 1 second");
            }
        }, 1000);
    }
}

If in any chance @Configuration annotation is not working so put @EnableConfigurationProperties at main running class. Make sure that you put @EnableScheduling at Application class, so main runnable class will look like

@SpringBootApplication
@EnableScheduling
@EnableConfigurationProperties
public class MainApplication implements CommandLineRunner {
    
    @Autowired
    MyTaskScheduler myTaskScheduler;

    public static void main(String[] args) {
        final Logger logger = LogManager.getLogger(MainApplication.class);
        SpringApplication.run(MainApplication.class, args);
        logger.info("Application started");
    }

    @Override
    public void run(String... args) throws Exception {
        myTaskScheduler.schedule();
    }
}

AlexElin
  • 1,044
  • 14
  • 23
Abrar Khan
  • 376
  • 3
  • 12
0

This answer is similar to the two previous ones, but is more compact because it leverages the scheduling registrar already provided in the application context:

@Configuration
@EnableScheduling
public class Schedule implements SchedulingConfigurer {

    private final transient WorkflowTriggerService workflowTriggerService;

    public Schedule(final WorkflowTriggerService workflowTriggerService) {
        this.workflowTriggerService = workflowTriggerService;
    }

    @Override
    public void configureTasks(final ScheduledTaskRegistrar taskRegistrar) {
        for (final WorkflowTrigger trigger : workflowTriggerService.getWorkflowTriggersWithSchedules()) {
            taskRegistrar.addCronTask(new WorkflowTask(trigger), trigger.getSchedule());
        }
    }

}

Each WorkflowTrigger returned by the service has its own cron schedule, and therefore allows dynamic registration of scheduled tasks that are not known at compilation time.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
chaserb
  • 1,340
  • 1
  • 14
  • 25