Spring scheduler which is run after application is started and after midnight
Asked Answered
E

9

24

How to describe Spring scheduler which is run after application is started and after 00:00 ?

Effie answered 4/5, 2013 at 18:33 Comment(0)
D
58

I would do this with two separate constructs.

For after the application starts, use @PostConstuct, and for every night at midnight use @Scheduled with the cron value set. Both are applied to a method.

public class MyClass {
    @PostConstruct
    public void onStartup() {
        doWork();
    }

    @Scheduled(cron="0 0 0 * * ?")
    public void onSchedule() {
        doWork();
    }

    public void doWork() {
        // your work required on startup and at midnight
    }
}
Depreciable answered 4/5, 2013 at 18:58 Comment(6)
What happens if the application is started at midnight? Would doWork be executed twice?Bewray
@LucasKreutz that is a bit nuanced. I imagine it depends on when Spring starts its scheduler. If a startup occurred around midnight, with the scheduler being ready before midnight, I would assume that the doWork method would be invoked multiple times in quick succession.Depreciable
Got it. It actually makes sense. Thanks for the explanation!Bewray
To make scheduling work, add @EnableScheduling annotationCousin
Avoid PostConstruct! This is immediately after the object is constructed. There are probably dependencies which are still not there. Await the ApplicationReadyEvent like described in proposal of Philippe Gibert instread.Efrem
I agree with @Maik, you might get sideeffectsHeteronym
D
19

A little about this subject, you can use @EventListener annotation.

Here is an example :

@Component
public class MyScheduler {

    @EventListener(ApplicationReadyEvent.class)
    public void onSchedule() {
        doWork();
    }

    public void doWork() {
        // your work required on startup
    }
}
Darkling answered 11/12, 2018 at 8:3 Comment(0)
E
9

Combination of solution of nicholas.hauschild and Philippe Gibert. Reason: @PostConstruct is probably not what you want because you may need other services which are still not started.

public class MyClass {

    @EventListener(ApplicationReadyEvent.class)
    @Scheduled(cron="0 0 0 * * ?")
    public void onSchedule() {
        doWork();
    }

    public void doWork() {
        // your work required on startup and at midnight
    } 
  
}

Consider to catch exceptions inside doWork().

Efrem answered 27/1, 2023 at 12:14 Comment(2)
this is very neat and tidy and avoids PostConstruct problems. ThanksConsortium
I like this solution. It's very short and doesn't require two different methods just for those two different annotations.Anticipate
O
4

At first you should add @EnableScheduling annotation for your application config.

The second add @Component or @Service annotation for your scheduler. And if you are using Scheduled annotation it runs automatically after initialization to change it you can use initialDelay parameter in annotation.

Here is complete example

@Component
public class MyScheduler {

    @Scheduled(cron="*/10 * * * * *")
    public void onSchedule() {
        doWork();
    }

    public void doWork() {
        // your work required on startup and at midnight
    }
}
Optimal answered 6/7, 2016 at 13:28 Comment(2)
How about call method after application start? The question was how to do this two requirementsEffie
What about annotation @Controller?Endospore
L
1

There is a little problrm: when you try to compound two way of start your job, like

    @Scheduled(cron = "0/15 * * * * *")
    @EventListener(ApplicationReadyEvent.class)

than first time you job starts to work in main thread by listener, and another in scheduling thread by schedulingExcutor. And 2 threads can start to do the same job, even if the first thred hasn't stopped yet! fg:

    @Scheduled(cron = "0/15 * * * * *")
    @EventListener(ApplicationReadyEvent.class)
    public void doWork()  {
      log.info("I'm working!!!!!");
        try {
            TimeUnit.SECONDS.sleep(60);
        } catch (InterruptedException e) {
            log.info("I was interrupted!");
        }
        log.info("I finished work");
    }

log:

16:32:36.086  INFO 34472 --- [           main] hello.jobs.CronJob: I'm working!!!!!
16:32:45.005  INFO 34472 --- [   scheduling-1] hello.jobs.CronJob: I'm working!!!!!
16:33:36.090  INFO 34472 --- [           main] hello.jobs.CronJob: I finished work
16:33:45.011  INFO 34472 --- [   scheduling-1] hello.jobs.CronJob: I finished work
Labourer answered 11/8, 2023 at 13:34 Comment(0)
M
0

We have multiple approaches to execute it, The suggested approach by the @nicholas.hauschild is correct and easier than any other approach, but with the @PostConstruct we must be careful not to use the method of the dependent bean. That bean may not have been initialized yet and cause a NullPointerException.

So we can implement CommandLineRunner or ApplicationRunner and implement the run method, So by that run method will be automatically invoked after all beans are initialized and the app has been started.

   @Component
   public class CommandLineAppStartupRunner implements CommandLineRunner {
        @Autowired
        private MyClass MyClass;

        @Override
        public void run(String...args) throws Exception {
           myService.doWork();

        }
    } 
Moffit answered 19/5, 2021 at 15:1 Comment(0)
S
0

okay, as I understand you want to run your schedule job once the app is started and at every midnight.

Spring Scheduler offers initialDelay but you have to use it with fixedDelay.

here is my answer:

// it runs after 30 seconds of startup, you will be dead before it runs again.

@Scheduled(initialDelay = 1000 * 30, fixedDelay=Long.MAX_VALUE)
public void runAtStartup(){
   doWork();
}

// runs every midgnight (12.00 AM)
@Scheduled(cron="0 0 0 * * ?")
public void onSchedule() {
   doWork();
}

Soupy answered 4/2, 2022 at 7:47 Comment(0)
D
-1
public class MyClass {
    @PostConstruct
    @Scheduled(cron="0 0 0 * * ?")
    public void doWork() {
        // your work 
    }
}
Decretal answered 17/9, 2020 at 9:30 Comment(2)
Comments would improve this answer.Betz
@EnableScheduling annotation is required, this code as such didn't worked.Cousin
A
-2

Understanding more about it follow this link https://www.baeldung.com/cron-expressions

For the specific task to be done at midnight there is a predefined annotation that can help , try @midnight. It should work:

    @midnight
    public void midnightRun(){
       doTheWork();
    }
Antisepsis answered 12/3, 2019 at 9:45 Comment(1)
Pretty sure this does not work. There is no @midnight annotation that I can find. Add to that, cron expressions should accept the phrase @midnight instead of the stars-and-numbers. Either way, this doesn't work with my Spring Scheduler at all. Midnight or Daily is 0 0 0 * * * using the Spring Scheduler.Billet

© 2022 - 2024 — McMap. All rights reserved.