I implemented some scheduled jobs in my micronaut application with the @Scheduled - annotation like described here: https://guides.micronaut.io/latest/micronaut-scheduled-gradle-java.html
This works just fine except that all jobs get executed before the application startup is completed. That is a problem because my startup process contains executing of db update jobs and stuff that needs to be done before everything else.
So how do I force all scheduled jobs to wait until the application start process is finished?
With "finished" I mean the moment
[main] INFO io.micronaut.runtime.Micronaut - Startup completed in 9127ms. Server Running: http://localhost:8080
appears in my console.
I know I could schedule all my jobs manually, but that would mean to implement an event listener to all my classes that contains scheduled tasks. I don't want to rely on other devs to remember this and it sounds like too much work for such a simple requirement.
The simplest way to achieve it is to use Micronaut 4 expression language and an event listener.
Given the following job we are using the expression language value #{!this.paused}
to pause the job unless the boolean flag paused
is set to false
.
@Singleton
public class SomeJob {
private boolean paused = true;
@Scheduled(fixedRate = "5m", condition = "#{!this.paused}" )
public void doSomething() {
System.out.println("The job runs...");
}
public boolean isPaused() {
return paused;
}
@EventListener
public void onStartup(StartupEvent event) {
this.paused = false;
}
}
Note that the expression language is a Micronaut 4 feature and not available in previous versions of Micronaut.
If you have multiple jobs you could implement something like this.
public sealed interface Pausable {
void pause();
void unpause();
@Singleton
final class SomeJobA implements Pausable {
private boolean paused = true;
@Scheduled(fixedRate = "5m", condition = "#{!this.paused}" )
public void doSomething() {
System.out.println("The job runs...");
}
@Override
public void pause() { this.paused = true; }
@Override
public void unpause() { this.paused = false; }
}
@Singleton
final class SomeJobB implements Pausable {
private boolean paused = true;
@Scheduled(fixedRate = "5m", condition = "#{!this.paused}" )
public void doSomething() {
System.out.println("The job runs...");
}
@Override
public void pause() { this.paused = true; }
@Override
public void unpause() { this.paused = false; }
}
}
Then you implement the event listener in your Application.java
.
@Singleton
public class Application {
private static ApplicationContext ctx;
public static void main(String[] args) {
ctx = Micronaut.run(Application.class, args);
}
@EventListener
public void onStartup(StartupEvent event) {
ctx.getBeansOfType(Pausable.class).forEach(Pausable::unpause);
}
}