What is the best way/choice for running scheduled ...
# questions
c
What is the best way/choice for running scheduled tasks/jobs within a Grails 6 application? I thought there was support for Quartz, but the plugin seems dated
j
You can use the quartz plugin (it was recently updated), you can use the spring starter (what I use), or you can use any java library
I think @James Fredley uses JobRunnr
This is my configuration to setup quartz in grails:
```
@Configuration
class QuartzConfiguration {
/**
* Wire up the correct datasource for Quartz jobs
*/
@Bean
@Order(0)
SchedulerFactoryBeanCustomizer dataSourceCustomizer(DataSource dataSource, ObjectProvider<PlatformTransactionManager> transactionManagerProvider) {
PlatformTransactionManager transactionManager = transactionManagerProvider.getIfUnique()
if(!transactionManager) {
throw new IllegalStateException("Transaction Manager could not be found.")
}
return (schedulerFactoryBean) -> {
schedulerFactoryBean.setDataSource(dataSource)
schedulerFactoryBean.setTransactionManager(transactionManager)
}
}
}```
This was my config:
spring.quartz.autoStartup = false //this must never be enabled as it will cause quartz to be initialized before grails has finished initializing
spring.quartz.'job-store-type' = 'jdbc'
spring.quartz.jdbc.'initialize-schema' = 'never'
spring.quartz.jdbc.'overwrite-existing-jobs' = true
spring {
quartz {
properties {
org {
quartz {
scheduler {
instanceName = 'my_quartz_cluster'
instanceId = 'AUTO'
skipUpdateCheck = true
}
threadPool.class = 'org.quartz.simpl.SimpleThreadPool'
threadPool {
threadCount = 5
threadPriority = Thread.NORM_PRIORITY
}
jobStore.class = 'org.springframework.scheduling.quartz.LocalDataSourceJobStore'
jobStore {
isClustered = true
misfireThreshold = 60000
driverDelegateClass = 'org.quartz.impl.jdbcjobstore.PostgreSQLDelegate'
useProperties = false
tablePrefix = 'QRTZ_'
clusterCheckinInterval = 5000
acquireTriggersWithinLock = true
}
}
}
}
}
}
I have some code that starts quartz as part of the app startup process. Also, my gradle file looks like this:
```
//Quartz
implementation "org.springframework.boot:spring-boot-starter-quartz"
implementation "org.quartz-schedulerquartz${project.'quartz.version'}"```
You can start quartz by injecting
Scheduler quartzScheduler
and then calling start on it
i also define all of my triggers , etc on the job, then iterate over all jobs to create those at startup
c
Very nice! I'll check it out and revert back if I have other questions, Thanks!
👍 2
j
I probably should release a "quartz lite" plugin
if it's not obvious, this is a cluster based config
and i add a migration to add the tables on startup if they don't exist (using the db migration)
🙌 1
quartz also has all of the sql files you need for each db, i'm using postgres in that example
c
Nice, I usually use postgres as db of choice
j
All of my jobs extend a common class that makes creating the jobkey + trigger trivial
so in my service where i start the quartz process, i do something like this:
Copy code
grailsApplication.mainContext.getBeansOfType(ManagedJob).values().collectEntries { [it.jobKey, it] }
then it's easy to iterate over the keys and delete anything that doesn't still exist
or create if it needs to
and there's a method
getTriggers
on my ManagedJob as well, so I can do this:
```jobInstance.triggers.each { Trigger trigger ->
def triggerName = trigger.key.name
def existing = triggerMap.get(triggerName)
def reschedule = true
if (existing instanceof CronTrigger && trigger instanceof CronTrigger
&& existing.cronExpression == trigger.cronExpression
&& existing.timeZone == trigger.timeZone) {
reschedule = false
}
if (reschedule) {
log.info("${existing ? 'Reschedule' : 'Add'} trigger ${trigger.key} for job ${jobKey} to quartz scheduler")
scheduleTrigger(trigger)
}
}```
it keeps it trivial and easy to maintain going forward.
j
I use the Quartz plugin in a handful of Grails 6 apps, it works fine:
Copy code
implementation 'org.grails.plugins:quartz:3.0.0'