In my steps below, I’m using Grails 2.0.0 and Quartz 2.1.1. I’m also connecting to a local DB2 database.
1. Run “grails clean” on your application.
2. Add the “quartz-all-2.1.1.jar” and “c3p0-0.9.1.1.jar” (in the lib folder of your Quartz download) to your lib directory.
3. Right click on your Grails project and chose “Grails Tools -> Refresh Dependencies” (Alt+G, R)
* Note: You will need run steps 1 – 3 in order to get Grails to link the dependencies.
4. Add your Quartz.properties file to your “conf” directory (or somewhere else on your classpath). Here’s the Quartz.properties file I used (you’ll need to change the username and password).
#============================================================================ # Configure Main Scheduler Properties #============================================================================ org.quartz.scheduler.instanceName = MyClusteredScheduler org.quartz.scheduler.instanceId = AUTO #============================================================================ # Configure ThreadPool #============================================================================ org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 25 org.quartz.threadPool.threadPriority = 5 #============================================================================ # Configure JobStore #============================================================================ org.quartz.jobStore.misfireThreshold = 60000 org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.useProperties = false org.quartz.jobStore.dataSource = myDS org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.isClustered = true org.quartz.jobStore.clusterCheckinInterval = 20000 #============================================================================ # Configure Datasources #============================================================================ org.quartz.dataSource.myDS.driver = com.ibm.db2.jcc.DB2Driver org.quartz.dataSource.myDS.URL = jdbc:db2://localhost:50001/BATCH org.quartz.dataSource.myDS.user = <some user> org.quartz.dataSource.myDS.password = <some password> org.quartz.dataSource.myDS.maxConnections = 5 org.quartz.dataSource.myDS.validationQuery=select 0 from dual
5. In your Config.groovy file, add or modify you “grails.config.locations” property. Here’s what I added:
grails.config.locations = [ "classpath:conf/Quartz.properties" ]
6. I added the JobScheduler and HelloJob java classes to my src/java directory. These could be groovy or whatever, but I just stole the example from Quartz to get it working correctly.
JobScheduler.java
package sample.quartz.scheduler; import static org.quartz.JobBuilder.newJob; import static org.quartz.TriggerBuilder.newTrigger; import static org.quartz.CronScheduleBuilder.*; import org.apache.log4j.Logger; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.Trigger; import org.quartz.impl.StdSchedulerFactory; public class JobScheduler { private static Logger log = Logger.getLogger(JobScheduler.class); private static JobScheduler JOB_SCHEDULER = new JobScheduler(); private Scheduler scheduler = null; public JobScheduler() { } public static JobScheduler getInstance() { return JOB_SCHEDULER; } public void startup() { try { // and start it off scheduler = StdSchedulerFactory.getDefaultScheduler(); System.out.println("NAME: " + scheduler.getSchedulerName()); scheduler.start(); // define the job and tie it to our HelloJob class JobDetail job = newJob(HelloJob.class) .withIdentity("job1", "group1") .build(); // Trigger a job that repeats every 20 seconds Trigger trigger = newTrigger() .withIdentity("trigger1", "group1") .withSchedule(cronSchedule("0/20 * * * * ?")) .build(); System.out.println("Starting Jobs"); // Tell quartz to schedule the job using our trigger scheduler.scheduleJob(job, trigger); scheduler.start(); } catch (SchedulerException se) { se.printStackTrace(); } } public void shutdown() { try { scheduler.shutdown(); } catch (SchedulerException se) { se.printStackTrace(); } } }
HelloJob.java
package sample.quartz.scheduler; import java.util.Date; import org.apache.log4j.Logger; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; public class HelloJob implements Job { private static Logger log = Logger.getLogger(HelloJob.class); public HelloJob() { } public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("Hello! HelloJob is executing. " + new Date()); } }
7. In your BootStrap.groovy file, add…
import sample.quartz.scheduler.JobScheduler class BootStrap { def init = { servletContext -> JobScheduler.getInstance().startup() } def destroy = { JobScheduler.getInstance().shutdown() } }
That’s it! Start your server. I tested it by running two servers. So,
grails -Dserver.port=8080 run-app
and then
grails -Dserver.port=8090 run-app
You will see that the first server to come up will run the HelloJob.java. I then tested the cluster by shutting off the first server. The second server picked up the scheduler (within 20 seconds, since that’s what was specified in the property file) and started running with it.
One problem I ran into trying to set this up was the error below. I had forgotten to c3po-0.9.1.1.jar along with quartz-all-2.1.1jar to the lib directory. Once I did that (and refreshed the dependencies), this error went away.
Issue:
ERROR context.GrailsContextLoader - Error executing bootstraps: java.lang.NoClassDefFoundError: com/mchange/v2/c3p0/ComboPooledDataSource
Hope that helps.
This is good information. My quartz.properties file was not being found with the string “classpath:conf/Quartz.properties”. However, once I removed the conf directory and used “classpath:Quartz.properties” the file was picked up.
The thread here talks about how grails copies files from certain folders and puts them on the classpath, not entire folders. http://grails.1312388.n4.nabble.com/Where-to-put-classpath-resources-td3050347.html
i m getting this error. could u tell me why it is.
NAME: MyClusteredScheduler
| Error 2014-06-30 05:55:54,233 [localhost-startStop-1] ERROR jdbcjobstore.JobStoreTX – ClusterManager: Error managing cluster: Failure identifying failed instan
heduler_state’ doesn’t exist
Message: Failure identifying failed instances when checking-in: Table ‘schedulerproject.qrtz_scheduler_state’ doesn’t exist
Line | Method
->> 3343 | findFailedInstances in org.quartz.impl.jdbcjobstore.JobStoreSupport
– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
| 3393 | clusterCheckIn in ”
| 3263 | doCheckin . . . . . . . . . . . in ”
| 3869 | manage in org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager
| 3854 | initialize . . . . . . . . . . . in ”
| 678 | schedulerStarted in org.quartz.impl.jdbcjobstore.JobStoreSupport
| 526 | start . . . . . . . . . . . . . in org.quartz.core.QuartzScheduler
| 143 | start in org.quartz.impl.StdScheduler
| 32 | startup . . . . . . . . . . . . in JobScheduler
| 5 | doCall in BootStrap$_closure1
| 308 | evaluateEnvironmentSpecificBlock in grails.util.Environment
| 301 | executeForEnvironment in ”
| 277 | executeForCurrentEnvironment . . in ”
| 334 | innerRun in java.util.concurrent.FutureTask$Sync
| 166 | run . . . . . . . . . . . . . . in java.util.concurrent.FutureTask
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . . . . . . . . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 722 | run in java.lang.Thread
Caused by MySQLSyntaxErrorException: Table ‘schedulerproject.qrtz_scheduler_state’ doesn’t exist
->> 411 | handleNewInstance in com.mysql.jdbc.Util
– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
| 386 | getInstance in ”
| 1052 | createSQLException . . . . . . . in com.mysql.jdbc.SQLError
| 4096 | checkErrorPacket in com.mysql.jdbc.MysqlIO
| 4028 | checkErrorPacket . . . . . . . . in ”
| 2490 | sendCommand in ”
| 2651 | sqlQueryDirect . . . . . . . . . in ”
| 2683 | execSQL in com.mysql.jdbc.ConnectionImpl
| 2144 | executeInternal . . . . . . . . in com.mysql.jdbc.PreparedStatement
| 2310 | executeQuery in ”
| 76 | executeQuery . . . . . . . . . . in com.mchange.v2.c3p0.impl.NewProxyPreparedStatement
| 2948 | selectSchedulerStateRecords in org.quartz.impl.jdbcjobstore.StdJDBCDelegate
| 3307 | findFailedInstances . . . . . . in org.quartz.impl.jdbcjobstore.JobStoreSupport
| 3393 | clusterCheckIn in ”
| 3263 | doCheckin . . . . . . . . . . . in ”
| 3869 | manage in org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager
| 3854 | initialize . . . . . . . . . . . in ”
| 678 | schedulerStarted in org.quartz.impl.jdbcjobstore.JobStoreSupport
| 526 | start . . . . . . . . . . . . . in org.quartz.core.QuartzScheduler
| 143 | start in org.quartz.impl.StdScheduler
| 32 | startup . . . . . . . . . . . . in JobScheduler
| 5 | doCall in BootStrap$_closure1
| 308 | evaluateEnvironmentSpecificBlock in grails.util.Environment
| 301 | executeForEnvironment in ”
| 277 | executeForCurrentEnvironment . . in ”
| 334 | innerRun in java.util.concurrent.FutureTask$Sync
| 166 | run . . . . . . . . . . . . . . in java.util.concurrent.FutureTask
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . . . . . . . . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 722 | run in java.lang.Thread
| Error 2014-06-30 05:55:54,357 [QuartzScheduler_MyClusteredScheduler-computer-11404122152056_MisfireHandler] ERROR jdbcjobstore.JobStoreTX – MisfireHandler: Err
misfires.
Message: Database error recovering from misfires.
Line | Method
->> 3197 | doRecoverMisfires in org.quartz.impl.jdbcjobstore.JobStoreSupport
– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
| 3946 | manage in org.quartz.impl.jdbcjobstore.JobStoreSupport$MisfireHandler
^ 3967 | run . . . . . . . in ”
Caused by MySQLSyntaxErrorException: Table ‘schedulerproject.qrtz_triggers’ doesn’t exist
->> 411 | handleNewInstance in com.mysql.jdbc.Util
– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
| 386 | getInstance in ”
| 1052 | createSQLException in com.mysql.jdbc.SQLError
| 4096 | checkErrorPacket in com.mysql.jdbc.MysqlIO
| 4028 | checkErrorPacket in ”
| 2490 | sendCommand in ”
| 2651 | sqlQueryDirect . in ”
| 2683 | execSQL in com.mysql.jdbc.ConnectionImpl
| 2144 | executeInternal . in com.mysql.jdbc.PreparedStatement
| 2310 | executeQuery in ”
| 76 | executeQuery . . in com.mchange.v2.c3p0.impl.NewProxyPreparedStatement
| 416 | countMisfiredTriggersInState in org.quartz.impl.jdbcjobstore.StdJDBCDelegate
| 3176 | doRecoverMisfires in org.quartz.impl.jdbcjobstore.JobStoreSupport
| 3946 | manage in org.quartz.impl.jdbcjobstore.JobStoreSupport$MisfireHandler
^ 3967 | run . . . . . . . in ”
Starting Jobs
| Error 2014-06-30 05:55:54,369 [MyClusteredScheduler_QuartzSchedulerThread] ERROR core.ErrorLogger – An error occurred while scanning for the next triggers to f
Message: Couldn’t acquire next trigger: Table ‘schedulerproject.qrtz_triggers’ doesn’t exist
Line | Method
->> 2840 | acquireNextTrigger in org.quartz.impl.jdbcjobstore.JobStoreSupport
– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
| 2755 | execute in org.quartz.impl.jdbcjobstore.JobStoreSupport$41
| 3810 | executeInNonManagedTXLock in org.quartz.impl.jdbcjobstore.JobStoreSupport
| 2751 | acquireNextTriggers in ”
^ 264 | run . . . . . . . . . . . in org.quartz.core.QuartzSchedulerThread
Caused by MySQLSyntaxErrorException: Table ‘schedulerproject.qrtz_triggers’ doesn’t exist
->> 411 | handleNewInstance in com.mysql.jdbc.Util
– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
| 386 | getInstance in ”
| 1052 | createSQLException . . . in com.mysql.jdbc.SQLError
| 4096 | checkErrorPacket in com.mysql.jdbc.MysqlIO
| 4028 | checkErrorPacket . . . . in ”
| 2490 | sendCommand in ”
| 2651 | sqlQueryDirect . . . . . in ”
| 2683 | execSQL in com.mysql.jdbc.ConnectionImpl
| 2144 | executeInternal . . . . . in com.mysql.jdbc.PreparedStatement
| 2301 | executeQuery in ”
| 76 | executeQuery . . . . . . in com.mchange.v2.c3p0.impl.NewProxyPreparedStatement
| 2570 | selectTriggerToAcquire in org.quartz.impl.jdbcjobstore.StdJDBCDelegate
| 2781 | acquireNextTrigger . . . in org.quartz.impl.jdbcjobstore.JobStoreSupport
| 2755 | execute in org.quartz.impl.jdbcjobstore.JobStoreSupport$41
| 3810 | executeInNonManagedTXLock in org.quartz.impl.jdbcjobstore.JobStoreSupport
| 2751 | acquireNextTriggers in ”
^ 264 | run . . . . . . . . . . . in org.quartz.core.QuartzSchedulerThread
org.quartz.JobPersistenceException: Couldn’t determine job existence (group1.job1): Unknown column ‘SCHED_NAME’ in ‘where clause’ [See nested exception: com.mysql
nown column ‘SCHED_NAME’ in ‘where clause’]
| Server running. Browse to http://localhost:8090/SchedulerProject
| Error 2014-06-30 05:57:22,256 [QuartzScheduler_MyClusteredScheduler-computer-11404122152056_ClusterManager] ERROR jdbcjobstore.JobStoreTX – ClusterManager: Err
nces when checking-in: Table ‘schedulerproject.qrtz_scheduler_state’ doesn’t exist
Message: Failure identifying failed instances when checking-in: Table ‘schedulerproject.qrtz_scheduler_state’ doesn’t exist
Line | Method
->> 3343 | findFailedInstances in org.quartz.impl.jdbcjobstore.JobStoreSupport
– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
| 3393 | clusterCheckIn in ”
| 3263 | doCheckin . . . . . in ”
| 3869 | manage in org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager
^ 3906 | run . . . . . . . . in ”
Caused by MySQLSyntaxErrorException: Table ‘schedulerproject.qrtz_scheduler_state’ doesn’t exist
->> 411 | handleNewInstance in com.mysql.jdbc.Util
– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
| 386 | getInstance in ”
| 1052 | createSQLException in com.mysql.jdbc.SQLError
| 4096 | checkErrorPacket in com.mysql.jdbc.MysqlIO
| 4028 | checkErrorPacket . in ”
| 2490 | sendCommand in ”
| 2651 | sqlQueryDirect . . in ”
| 2683 | execSQL in com.mysql.jdbc.ConnectionImpl
| 2144 | executeInternal . . in com.mysql.jdbc.PreparedStatement
| 2301 | executeQuery in ”
| 76 | executeQuery . . . in com.mchange.v2.c3p0.impl.NewProxyPreparedStatement
| 2948 | selectSchedulerStateRecords in org.quartz.impl.jdbcjobstore.StdJDBCDelegate
| 3307 | findFailedInstances in org.quartz.impl.jdbcjobstore.JobStoreSupport
| 3393 | clusterCheckIn in ”
| 3263 | doCheckin . . . . . in ”
| 3869 | manage in org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager
^ 3906 | run . . . . . . . . in ”
| Error 2014-06-30 05:58:50,285 [QuartzScheduler_MyClusteredScheduler-computer-11404122152056_ClusterManager] ERROR jdbcjobstore.JobStoreTX – ClusterManager: Err
nces when checking-in: Table ‘schedulerproject.qrtz_scheduler_state’ doesn’t exist
Message: Failure identifying failed instances when checking-in: Table ‘schedulerproject.qrtz_scheduler_state’ doesn’t exist
Line | Method
->> 3343 | findFailedInstances in org.quartz.impl.jdbcjobstore.JobStoreSupport
– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
| 3393 | clusterCheckIn in ”
| 3263 | doCheckin . . . . . in ”
| 3869 | manage in org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager
^ 3906 | run . . . . . . . . in ”
Caused by MySQLSyntaxErrorException: Table ‘schedulerproject.qrtz_scheduler_state’ doesn’t exist
->> 411 | handleNewInstance in com.mysql.jdbc.Util
– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
| 386 | getInstance in ”
| 1052 | createSQLException in com.mysql.jdbc.SQLError
| 4096 | checkErrorPacket in com.mysql.jdbc.MysqlIO
| 4028 | checkErrorPacket . in ”
| 2490 | sendCommand in ”
| 2651 | sqlQueryDirect . . in ”
| 2683 | execSQL in com.mysql.jdbc.ConnectionImpl
| 2144 | executeInternal . . in com.mysql.jdbc.PreparedStatement
| 2301 | executeQuery in ”
| 76 | executeQuery . . . in com.mchange.v2.c3p0.impl.NewProxyPreparedStatement
| 2948 | selectSchedulerStateRecords in org.quartz.impl.jdbcjobstore.StdJDBCDelegate
| 3307 | findFailedInstances in org.quartz.impl.jdbcjobstore.JobStoreSupport
| 3393 | clusterCheckIn in ”
| 3263 | doCheckin . . . . . in ”
| 3869 | manage in org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager
^ 3906 | run . . . . . . . . in ”
Terminate batch job (Y/N)? y