springspring-bootcronspring-scheduled

Spring Boot @Scheduled annotation: Start and end at top of hour?


I'm using the @Scheduled annotation with a cron expression to schedule recurring tasks during the work day. What I would like to do is to run the first job at 8:00, then every 15 minutes ending at 17:00 inclusive. I can easily get jobs from 8:00 to 16:45, but the (all-important) last invocation eludes me. Is it possible to do this in a cron expression?

Right now I'm using two functions, one annotated with

@Scheduled(cron = "0 */15 8-16 * * MON-FRI")

and another with

@Scheduled(cron = "0 0 17 * * MON-FRI")

where the latter simply calls the former. This works, but ideally I'd like to make this configurable in application.properties with a single expression.

I also thought about just running a job every 15 minutes, configuring a start and end time and checking whether the system time is inside the configured interval. That strikes me as a little bit ugly because the 17:00 invocation will do the check at 17:00 plus an unspecified amount of time, but in practice that amount of time should be tiny and checking for < 17:01 should be okay unless something else has already gone terribly wrong.

So there are workarounds available, but I'd consider it most elegant to have a single expression to rule them all, as it were. Trouble is, I can't figure out a way to get the 17:00 invocation in there without also getting 17:15, 17:30, and 17:45.

Ending at 17:00 sharp is more important than starting at 8:00 sharp, so an expression that starts at 8:15 and ends at 17:00 would be all right for this particular purpose. I can't figure out how to get that into a cron expression, either.

Is it possible and I'm just too blind to see the way, or am I barking up the wrong tree? If the latter, is there another elegant way to get the invocation pattern I want?


Solution

  • From the CronExpression javadoc , spring just implement the crontab expression described at this. Reading this man page and don't think it has some special syntax that allows represent your use-case using just single expression. So representing it by two expressions like what you are currently do is already the simplest and most elegant out of the box solution to me.

    If you really want to define all cron expressions in a single line in application.properties, you could define it as a CSV value in application.properties and then read the cron expression one by one and programmatically register a cron job for each expression by implementing SchedulingConfigurer (Refer to this).

    Something like :

    application.properties :

    app.crontabs=0 */15 8-16 * * MON-FRI,0 0 17 * * MON-FRI
    

    And the application configuration :

    @EnableScheduling
    @Configuration
    public class CronJobConfig implements SchedulingConfigurer {
    
       
        @Value("${app.crontabs}")
        private List<String> crontabs;
    
    
        @Bean(destroyMethod = "shutdown")
        public Executor taskExecutor() {
            return Executors.newScheduledThreadPool(100);
        }
    
        private void runCronJob(){
          //your cron job
        }
    
       
        @Override
        public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
            taskRegistrar.setScheduler(taskExecutor());
            for(String cron : crontabs){
                taskRegistrar.addCronTask(()->runCronJob() , cron);
            }
        }
    }