eXo Platform uses Quartz Scheduler, the Java Framework for scheduling jobs, in a wide range of features. When eXo Platform runs in the cluster mode, it is important to prevent the duplicated execution of jobs. Quartz has its own cluster mode, with each instance of eXo Platform server as a member of Quartz load balancing and failover group.
In this guideline, Quartz is configured to use the JDBC Job Store method that allows Quartz members to share the same database. Load balancing occurs automatically, when a member acquires to execute the job as fast as it can, by placing a lock on the job so that it is not executed by other members. Failover occurs when a node fails in the midst of job execution, and one of the others will take the job over. The acquiring node is "more or less random", as said in Quartz reference.
There are two options of JDBC Job Store: JobStoreTX is supposed to be used in the Quartz standalone application, and JobStoreCMT is supposed to be part of a larger transaction management. Both of them work in eXo Platform.
Although Quartz can connect to the database directly using JDBC driver, in eXo Platform it should be configured to use a JNDI datasource.
The Quartz library is packed with eXo Platform already and you do not need to download and install Quartz. However, Quartz JDBC Job Store requires a database that you will initiate using a SQL script. You will be instructed to obtain the script later in this document.
As noticed in this chapter, Cluster mode is temporarily not supported in the Tomcat bundle. But JDBC Job Store still works in the Tomcat bundle. So in this document, the instruction is provided for both JBoss and Tomcat but it does not mean to reverse the notice.
There will be differences in detailed steps for JBoss and Tomcat. To make it easy to follow, here is a summary of steps for both:
Initiate the Quartz database, named quartz_lb in this document.
Declare a datasource of which JNDI name is java:/comp/env/exo-quartz in this document.
Install the JDBC driver.
Add the startup option -Dorg.quartz.properties to tell where the properties file locates.
After the last step, you are instructed to confirm that Quartz cluster is working.
First, create a database and choose your desired name, for example quartz_lb. Then, import tables using the Quartz SQL script.
The scripts can be downloaded at http://svn.terracotta.org/svn/quartz/tags/quartz-2.1.6/docs/dbTables/.
For example, if you are using MySQL, you will download
The version of the above link is 2.1.6. This version is used by eXo Platform when the document is validated.
For later versions of eXo Platform, you may check the Quartz version by yourself.
Another possible way is to find the
quart*.jar in the eXo Platform package and check its
Quartz JNDI datasource
The datasource JNDI name will be java:/comp/env/exo-quartz in which you should not change the part: java:/comp/env. This datasource will connect to the quartz_lb database.
In the JBoss package, the datasource is added to the customized standalone file.
Because you are running the cluster mode, the file is generally
Here is an example using MySQL:
<datasource jta="true" jndi-name="java:/comp/env/exo-quartz" pool-name="quartz_lb" enabled="true" use-java-context="false">
You need to modify the JNDI name, the connection URL, username and password, and the driver according to your environment. Notice that the driver is the jar file name that you will install in next steps.
In the Tomcat bundle, the datasource is configured in the
$PLATFORM_TOMCAT_HOME/conf/server.xml file at first.
The configuration looks like below. Note the JNDI name element "java:/comp/env" is omitted because it will be automatically
added during the JNDI lookup:
<Resource name="exo-quartz" type="javax.sql.DataSource"
initialSize="5" maxActive="20" minIdle="5" maxIdle="15" maxWait="10000"
validationQuery="SELECT 1" validationQueryTimeout="5"
testWhileIdle="true" testOnBorrow="true" testOnReturn="false"
removeAbandoned="true" removeAbandonedTimeout="300" logAbandoned="false"
poolPreparedStatements="true" username="your_user_name" password="your_password"
driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/quartz_lb" />
Next, a resource link needs to be added to the
<ResourceLink name="exo-quartz" global="exo-quartz" type="javax.sql.DataSource"/>
You can configure the datasource similarly to the two default datasources: exo-jcr_portal and exo-idm_portal. If you need more details about the datasource configurations, visit Jacamar Schema Descriptor or Tomcat JDBC Connection Pool.
Installing JDBC driver
As you see in the datasource configuration, a driver jar file name is required. The driver may have been installed when you configure 2 datasources for IDM and JCR, as described in Database.
If not, install the jar to the
$PLATFORM_TOMCAT_HOME/lib folder in the Tomcat bundle or the
$PLATFORM_JBOSS_HOME/standalone/deployment folder in JBoss.
If you want to know which DBMSs are supported by Quartz, check the scripts here.
By default, the configurations for Quartz is loaded from the
quartz.properties file inside the jar package of Quartz.
You should create an external
quartz.properties file and place it under the folder:
$PLATFORM_TOMCAT_HOME/conf (in Tomcat).
$PLATFORM_JBOSS_HOME/standalone/configuration (in JBoss).
quartz.properties looks like below (See Quartz configuration reference for the full configuration explanation):
#============================================================================ # Configure Main Scheduler Properties #============================================================================ org.quartz.scheduler.instanceName = RHECMClusteredScheduler 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.JobStoreCMT org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.useProperties = false org.quartz.jobStore.dataSource = quartzDS org.quartz.jobStore.nonManagedTXDataSource = quartzDSNoTx org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.isClustered = true org.quartz.jobStore.clusterCheckinInterval = 20000 #============================================================================ # Configure Datasources #============================================================================ org.quartz.dataSource.quartzDS.jndiURL=java:/comp/env/exo-quartz org.quartz.dataSource.quartzDSNoTx.jndiURL=java:/comp/env/exo-quartz
In this guideline, you need to focus on two sections:
First, you see that you are using JobStoreCMT.
This method requires 2 datasource connections, one is transaction that is managed by the application, and another
is non-managed for Quartz's self-commit and rollback. So in the
jobStore section, you declare 2 names:
quartzDS and quartzDSNoTx.
These two logical datasources are achieved by the same JNDI name, java:/comp/env/exo-quartz which you declare in the previous steps.
If you want to use JobStoreTX instead of JobStoreCMT, you will remove the non-managed connection.
dataSource will be changed into:
#============================================================================ # 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 = quartzDS org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.isClustered = true org.quartz.jobStore.clusterCheckinInterval = 20000 #============================================================================ # Configure Datasources #============================================================================ org.quartz.dataSource.quartzDS.jndiURL=java:/comp/env/exo-quartz
For each type of DBMS, you need to set an appropriate value of the
Many databases are known to work with the StdJDBCDelegate driver, but some may require another delegated driver.
See the list of choices at JobStoreTX
Adding the -Dorg.quartz.properties option
You need to tell the server where to load the
quartz.properties file, by adding the startup option: -Dorg.quartz.properties.
In Tomcat, you need to customize environment variables, as described in
Customizing environment variables.
Once you have the
setenv-customize file, append the following line to it:
For Windows (.bat), the code is a bit different:
SET CATALINA_OPTS=%CATALINA_OPTS% -Dorg.quartz.properties=%CATALINA_HOME%/conf/quartz.properties
In JBoss, you can simply append the option to the start command. Consider that your start command is similar to the one described in Setting up eXo Platform cluster. After being appended, it will be:./standalone.sh -b 0.0.0.0 --server-config=standalone-exo-cluster.xml -Dorg.quartz.properties=standalone/configuration/quartz.properties
How to confirm the Quartz cluster is working
At the startup of each node, there should be some Quartz logs like the following:
17:21:55,283 INFO [org.quartz.core.QuartzScheduler] (ServerService Thread Pool -- 48) Quartz Scheduler v.2.1.6 created. 17:21:55,285 INFO [org.quartz.impl.jdbcjobstore.JobStoreCMT] (ServerService Thread Pool -- 48) Using db table-based data access locking (synchronization). 17:21:55,292 INFO [org.quartz.impl.jdbcjobstore.JobStoreCMT] (ServerService Thread Pool -- 48) JobStoreCMT initialized. 17:21:55,294 INFO [org.quartz.core.QuartzScheduler] (ServerService Thread Pool -- 48) Scheduler meta-data: Quartz Scheduler (v2.1.6) 'RHECMClusteredScheduler' with instanceId 'MAY1281381746115234' Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally. NOT STARTED. Currently in standby mode. Number of jobs executed: 0 Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 25 threads. Using job-store 'org.quartz.impl.jdbcjobstore.JobStoreCMT' - which supports persistence. and is clustered. 17:21:55,294 INFO [org.quartz.impl.StdSchedulerFactory] (ServerService Thread Pool -- 48) Quartz scheduler 'RHECMClusteredScheduler' initialized from specified file: '/media/data/doc/3054/test/plf-jboss-node1/standalone/configuration/quartz.properties'
Also, after the first node is started, you can check the Quartz database to see that Quartz successfully added some records.