How to set Dynamic Task Schedulers Programmatically using Spring Boot
If you are used to (or at least done some research) scheduling tasks in Kotlin or Java by using the Spring Framework, you’ve probably seen the @Scheduled annotation.
That’s fine, you can annotate a method, define a fixedDelay or a fixedRate or a Cron Expression and your method will be run following these rules.
@Scheduled(cron = "0 15 10 15 * ?")
fun scheduleTaskUsingCronExpression() {
val now = System.currentTimeMillis() / 1000
println("schedule tasks using cron jobs - $now")
}
That’s a nice and clean way of scheduling tasks and has done the job for me for the past years. I can even set the cron expression using the application.properties. Excusing myself of refactoring the code whenever I need to change the scheduler configuration:
@Scheduled(cron = "myfeature.scheduler.cron")
fun scheduleTaskUsingCronExpression() {
val now = System.currentTimeMillis() / 1000
println("schedule tasks using cron jobs - $now")
}
Although the @Scheduled annotation is a nice and clean solution that solves the problem most of the time, what if you need to set multiple schedulers based on different cron expressions? You would need to define multiple methods annotated with @Scheduled on each you would assign a different cron expression. And then, whenever you need a new scheduler, you would need to refactor the code and add a new method to hold the scheduler annotation:
@Scheduled(cron = "myfeature.scheduler.cron1")
fun scheduleTaskUsingCronExpression() {
runMyFunction()
}@Scheduled(cron = "myfeature.scheduler.cron2")
fun scheduleTaskUsingCronExpression() {
runMyFunction()
}
That’s the problem I faced and this is how I solved it.
The Solution
The first thing I wanted to do was to define my schedulers in my application.properties, which is basically a list of crons. I use application.yml instead, and that’s how it looks:
myfeature:
schedulers:
- cron: "0 0 6 * * *"
myvariable: "Raphael"
- cron: "0 15 14 * * *"
myvariable: "De"
- cron: "0 45 18 * * *"
myvariable: "Lio"
Then, I created a new Configuration class to hold the bean for a TaskScheduler pool:
@Configuration
@EnableScheduling
class SchedulerConfiguration {
@Bean
fun threadPoolTaskScheduler(): TaskScheduler {
val scheduler = ThreadPoolTaskScheduler()
scheduler.poolSize = 20
return scheduler
}
}
And a class annotated with @ConfigurationProperties to load my scheduler properties:
@Component
@ConfigurationProperties(prefix = "myfeature")
class MyProperties {
lateinit var schedulers: List<Scheduler>
}
class Scheduler {
lateinit var cron: String
lateinit var myvariable: String
}
Now that I have everything I need, I can implement my dynamic scheduler configuration which implements the SchedulingConfigurer interface provided by Spring. When implementing this interface, we are also requited to implement the configureTasks method which will define all schedulers at the start of the application and have them scheduled programmatically.
I iterate over my properties and register a new CronTask for each of them. These CronTasks will be scheduled at the start of the application.
I’m very happy you got to this part of the story, I‘m truly thankful for this.
Support my work: follow me and clap to this story.
Conclusion
And that’s it! Now I can add as many schedulers as I want to my properties and all of them will be scheduled at the start of the application with their own defined variable.
This solution is not as clean as the annotation @Scheduled, but it’s definitely more customizable.
I hope you have enjoyed the story and see you next time! 😄
Contribute
Writing takes time and effort. I love writing and sharing knowledge, but I also have bills to pay. If you like my work, please, consider donating through Buy Me a Coffee: https://www.buymeacoffee.com/RaphaelDeLio
Or by sending me BitCoin: 1HjG7pmghg3Z8RATH4aiUWr156BGafJ6Zw
Follow Me on Social Media
Stay connected and dive deeper into the world of Spring with me! Follow my journey across all major social platforms for exclusive content, tips, and discussions.