cjchalmers
07/14/2025, 7:24 PMjdaugherty
07/14/2025, 7:25 PMjdaugherty
07/14/2025, 7:25 PMjdaugherty
07/14/2025, 7:29 PM```
@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'}"```
jdaugherty
07/14/2025, 7:30 PMScheduler quartzScheduler
and then calling start on itjdaugherty
07/14/2025, 7:31 PMcjchalmers
07/14/2025, 7:31 PMjdaugherty
07/14/2025, 7:32 PMjdaugherty
07/14/2025, 7:33 PMjdaugherty
07/14/2025, 7:33 PMjdaugherty
07/14/2025, 7:34 PMcjchalmers
07/14/2025, 7:35 PMjdaugherty
07/14/2025, 7:35 PMjdaugherty
07/14/2025, 7:35 PMgrailsApplication.mainContext.getBeansOfType(ManagedJob).values().collectEntries { [it.jobKey, it] }
jdaugherty
07/14/2025, 7:36 PMjdaugherty
07/14/2025, 7:36 PMjdaugherty
07/14/2025, 7:37 PMgetTriggers
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)
}
}```
jdaugherty
07/14/2025, 7:38 PMJohn Moore
07/15/2025, 1:52 PMimplementation 'org.grails.plugins:quartz:3.0.0'