What version of Quartzite does this guide cover?

This guide covers Quartzite 2.0.x (including beta releases).

Overview

During Quartz operation, it has to do some housekeeping: track trigger execution history,
trigger and job state, misfires and so on. By default Quartz keeps this information
in memory. In some cases it is all you need but has obvious drawbacks:

If JVM is stopped, killed or crashes, all state is lost

Really large number of jobs and triggers may consume a lot of RAM

To address this issue, Quartz supports durable job stores. They
store all the scheduler state, not just information about jobs.

Available Durable Quartz Job Stores

Quartz comes with a JDBC-backed job data store out of the box. There is also a MongoDB-backed one.

Quartz and Clojure Class Loaders

Clojure is a compiled language: code is compiled when it is loaded (usually via clojure.core/require). To dynamically
load classes Clojure code compiles to, Clojure uses a special class loader. Since Quartz also uses its own class loader,
due to the JVM security model it cannot see job classes Clojure compiler generates.

A solution to this issue is described in the following section.

How to use durable job stores with Quartzite

With a SQL Database

Quartz provides several classes for JDBC-backed job stores. This solution was
tested using the JobStoreTX class which should be used in applications that
are not running inside an application server like Immutant or JBoss AS.

To allow Quartz to see classes the Clojure compiler generates, we must provide a
custom implementation of the ClassLoadHelper class which Quartz uses for
discovering classes. A working implementation is below:

Checkout the jobStore configuration options if you want to utilize a database other than PostgreSQL.

Finally, download the Quartz release from Quartz and navigate to the "docs/dbTables" subdirectory to find the SQL table-creation scripts. Run the script appropriate for your SQL backend and you should be all set!

With MongoDB

A solution to the different class loaders issue is to subclass the job store class and (if it allows this) make it use
Clojure's clojure.lang.DynamicClassLoader:

packagemegacorp.myservice.quartz;importclojure.lang.DynamicClassLoader;importcom.novemberain.quartz.mongodb.MongoDBJobStore;publicclassJobStoreextendsMongoDBJobStoreimplementsorg.quartz.spi.JobStore{@OverrideprotectedClassLoadergetJobClassLoader(){// makes it possible for Quartz to load and instantiate jobs that are defined// using defrecord without AOT compilation.returnnewDynamicClassLoader();}}

Future versions of Quartzite may ship with custom job classes like this out of the box.

Wrapping Up

Quartz provides support for durable stores for its state. Using a durable store
is a good idea for availability reasons. Due to specifics of how Clojure compiler
and Quartz scheduler work, using durable stores with Quartzite requires a little
bit of glue code. Quartzite authors continue looking for a good generic solution.