Grails clustering quartz jobs sample code and config desired

后端 未结 1 1554
名媛妹妹
名媛妹妹 2020-12-29 14:42

I am using the quartz plugin with Grails 1.3.7. I have a need to load balance/cluster a server app that uses quartz jobs. Apparently this is supported but I am finding that

相关标签:
1条回答
  • 2020-12-29 15:15

    To cluster the Quartz plugin in Grails, there are some files you need to include in your project. First, install the grails-app/conf/QuartzConfig.groovy and make sure jdbcStore is enabled.

    quartz {
        autoStartup = true
        jdbcStore = true
        waitForJobsToCompleteOnShutdown = true
    }
    

    Next, install the Hibernate configuration files relevant to the database to which you will be connecting. For example, with Oracle, the base Hibernate xml config at grails-app/conf/hibernate/hibernate.cfg.xml is:

    <?xml version='1.0' encoding='UTF-8'?>
    <!DOCTYPE hibernate-configuration PUBLIC
    '-//Hibernate/Hibernate Configuration DTD 3.0//EN'
    'http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd'>
    
    <hibernate-configuration>
    
    <session-factory>
        <mapping resource="Quartz.oracle.hbm.xml"/>
    </session-factory>
    
    </hibernate-configuration>
    

    The actual Quartz-Hibernate SQL file for this example will be named Quartz.oracle.hbm.xml and will reside in the same directory. These files should be available at the Quartz plugin on GitHub (https://github.com/nebolsin/grails-quartz), under src/templates/sql. Note, that these scripts only seem to work for DataSource create and create-drop, so you'll need to manually create the Quartz tables on an update, if they don't already exist from a previous run.

    Create a grails-app/conf/quartz/quartz.properties file, and edit is to fit your business needs:

    /* Have the scheduler id automatically generated for
     * all schedulers in a cluster */
    org.quartz.scheduler.instanceId = AUTO
    /* Don't let Quartz "Phone Home" to see if new versions
     * are available */
    org.quartz.scheduler.skipUpdateCheck = true
    
    org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
    /* Configure Quartz for only one thread as the only job
     * should run once per day */
    org.quartz.threadPool.threadCount = 4
    /* Give the thread a Thread.MIN_PRIORITY level*/
    org.quartz.threadPool.threadPriority = 1
    
    /* Allow a minute (60,000 ms) of non-firing to pass before 
     * a trigger is called a misfire */
    org.quartz.jobStore.misfireThreshold = 60000
    /* Handle only 2 misfired triggers at a time */
    org.quartz.jobStore.maxMisfiresToHandleAtATime = 2
    /* Check in with the cluster every 5000 ms*/
    org.quartz.jobStore.clusterCheckinInterval = 5000
    
    /* Use the Oracle Quartz Driver to communicate via JDBC */
    org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
    /* Have Quartz handle its own transactions with the database */
    org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
    
    /* Define the prefix for the Quartz tables in the database*/
    org.quartz.jobStore.tablePrefix = QRTZ_
    /* Tell Quartz it is clustered */
    org.quartz.jobStore.isClustered = true
    /* Tell Quartz that properties passed to the job call are
     * NOT all String objects */
    org.quartz.jobStore.useProperties = false
    
    /* Detect the jvm shutdown and call shutdown on the scheduler */
    org.quartz.plugin.shutdownhook.class = org.quartz.plugins.management.ShutdownHookPlugin
    org.quartz.plugin.shutdownhook.cleanShutdown = true
    
    /* Log the history of triggers and jobs */
    org.quartz.plugin.triggerHistory.class = org.quartz.plugins.history.LoggingTriggerHistoryPlugin
    org.quartz.plugin.jobHistory.class = org.quartz.plugins.history.LoggingJobHistoryPlugin
    

    Note from the above properties, you can set org.quartz.plugins in the Log4j setup of Config.groovy to log relevant job and trigger triggering information. I think info level should suffice.

    Edit, or create, scripts/_Events.groovy and add the following war modification closure. This fixes a known Quartz plugin bug to install the correct quartz.properties, instead of a blank one from the plugin, in to the final war file.

    eventCreateWarStart = { warName, stagingDir ->
        // Make sure we have the correct quartz.properties in the
        // correct place in the war to enable clustering
        ant.delete(dir:"${stagingDir}/WEB-INF/classes/quartz")
        ant.copy(file:"${basedir}/grails-app/conf/quartz/quartz.properties",
            todir:"${stagingDir}/WEB-INF/classes")
    }
    

    And you should be done...

    P.S. If you are using an Oracle database, add the following to BuildConfig.groovy in the dependencies block, so that you have access to the Quartz-Oracle communication drivers:

    runtime("org.quartz-scheduler:quartz-oracle:1.7.2") {
        // Exclude quartz as 1.7.3 is included from the plugin
        excludes('quartz')
    }
    

    P.P.S The sql files at the link above are just the SQL. To make it in to a hibernate file, just surround each individual SQL command with a Hibernate database-object node, like so (again w/ Oracle example):

    <?xml version='1.0' encoding='UTF-8'?>
    <!DOCTYPE hibernate-mapping PUBLIC
        '-//Hibernate/Hibernate Mapping DTD 3.0//EN'
        'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd'>
    
    <hibernate-mapping>
    
        <database-object>
            <create>
            CREATE TABLE QRTZ_JOB_DETAILS (
            JOB_NAME VARCHAR2(200) NOT NULL,
            JOB_GROUP VARCHAR2(200) NOT NULL,
            DESCRIPTION VARCHAR2(250) NULL,
            JOB_CLASS_NAME VARCHAR2(250) NOT NULL,
            IS_DURABLE VARCHAR2(1) NOT NULL,
            IS_VOLATILE VARCHAR2(1) NOT NULL,
            IS_STATEFUL VARCHAR2(1) NOT NULL,
            REQUESTS_RECOVERY VARCHAR2(1) NOT NULL,
            JOB_DATA BLOB NULL,
            PRIMARY KEY (JOB_NAME,JOB_GROUP)
            )
            </create>
            <drop>DROP TABLE QRTZ_JOB_DETAILS</drop>
            <dialect-scope name='org.hibernate.SomeOracleDialect' />
        </database-object>
    ...
        <database-object>
            <create>INSERT INTO QRTZ_LOCKS VALUES('TRIGGER_ACCESS')</create>
            <drop></drop>
            <dialect-scope name='org.hibernate.SomeOracleDialect' />
        </database-object>
    ...
    </hibernate-mapping>
    

    The dialect-scope tells Hibernate with which Database dialects the create and drop nodes should be used. You can try leaving it out and see if it works, otherwise you may have to add the MySql dialect used by your Grails DataSource.

    0 讨论(0)
提交回复
热议问题