1. opensymphony
  2. quartz

Source

quartz / docs / faq.html

<html>
<head>
	<title>Quartz - Frequenty Asked Questions</title>
</head>


<body>
<h3>General Questions:</h3>
<ul>
  <li><a href="#whatIs">What Is Quartz?</a></li>
  <li><a href="#timers">Why not just use java.util.Timer?</a></li>
  <li><a href="#build">How do I build the Quartz source?</a></li>
</ul>
<h3>Miscellaneous Questions: </h3>
<ul>
  <li><a href="#scalability">How many jobs is Quartz capable of running?</a></li>
  <li><a href="#rmi">I'm having issues with using Quartz via RMI -- HELP!?!</a></li>
</ul>
<h3>Questions about Jobs:  </h3>
<ul>
  <li><a href="#durability">How do I keep a Job from being removed after it completes?</a></li>
  <li><a href="#statefulness">How do I keep a Job from firing concurrently?</a></li>
  <li><a href="#abortJob">How do I stop a Job that is currently executing?</a></li>
</ul>
<h3>Questions about Triggers:</h3>
<ul>
	<li><a href="#chaining">How do I chain Job execution? Or, how do I create a workflow?</a></li>
	<li><a href="#notStarted">Why isn't my trigger firing?</a></li>
</ul>
<h3>Questions about JDBCJobStore:  </h3>
<ul>
  <li><a href="#jdbcjobstore">How do I improve the performance of JDBC-JobStore?</a></li>
  <li><a href="#connValidate">My DB Connections don't recover properly if the database server is restarted.</a></li>
</ul>

<h3>Questions about Transactions:  </h3>
<ul>
  <li><a href="#deadlocks">I'm using JobStoreCMT and I'm seeing deadlocks, what can I do?</a></li>
</ul>

<br />
<br />

<hr />

<a name="whatIs"></a><!-- Stupid IE bug... a tags cannot be singletons, or the style sheet
for the a tag is applied to all text until a closing a tag is found. -->
<h4>What is Quartz?</h4>

<p>Quartz is a job scheduling
system that can be integrated with, or used along side virtually any other
software system.  The term "job scheduler" seems to conjure different ideas for
different people.  As you read this tutorial, you should be able to get a firm
idea of what <i>we</i> mean when we use this term, but in short, a job scheduler
is a system that is responsible for executing (or notifying) other software
components when a pre-determined (scheduled) time arrives.</p>

<p>Quartz is quite flexible, and contains multiple usage paradigms that can be
used separately or together, in order to achieve your desired behavior, and
enable you to write your code in the manner that seems most 'natural' to your
project.</p>

<p>Quartz is very light-weight, and requires very little setup/configuration - it
can actually be used 'out-of-the-box' if your needs are relatively basic.</p>

<p>Quartz is fault-tolerant, and can persist ('remember') your scheduled jobs
between system restarts.</p>

<p>Although Quartz is extremely useful for simply running certain system
processes on given schedules, the full potential of Quartz can be realized when
you learn how to use it to drive the flow of your application's business
processes.</p>

<hr /><!-- ----------------------------------------------------------------------- -->

<a name="whatIsPt2"></a>
<h4>What is Quartz - From a Software Component View?</h4>

<p>Quartz is distributed as a small java library (.jar file) that contains all
of the core Quartz functionality.  The main interface (API) to this
functionality is the <i>Scheduler</i> interface.  It provides simple operations
such as scheduling/unscheduling jobs, starting/stopping/pausing the
scheduler.</p>

<p>If you wish to schedule your own software components for execution they must
implement the simple <i>Job</i> interface, which contains the method
<i>execute()</i>.  If you wish to have components notified when a scheduled
fire-time arrives, then the components should implement either the
<i>TriggerListener</i> or <i>JobListener</i> interface.</p>

<p>The main Quartz 'process' can be started and ran within your own application,
as a stand-alone application (with an RMI interface), or within a J2EE app.
server to be used as a resource by your J2EE components.</p>

<hr /><!-- ----------------------------------------------------------------------- -->

<a name="timers"></a>
<h4>Why not just use java.util.Timer?</h4>

<p>Since JDK 1.3, Java has "built-in" timer capabilities, through the
java.util.Timer and java.util.TimerTask classes - why would someone use
Quartz rather than these standard features?</p>

<p>There are many reasons! Here are a few:
<ol>
  <li>Timers have no persistence mechanism.</li>
  <li>Timers have inflexible scheduling (only able to set start-time & repeat
      interval, nothing based on dates, time of day, etc.)</li>
  <li>Timers don't utilize a thread-pool (one thread per timer)</li>
  <li>Timers have no real management schemes - you'd have to write your own
      mechanism for being able to remember, organize and retreive your tasks by
      name, etc.</li>
</ol>
</p>

<hr /><!-- ----------------------------------------------------------------------- -->

<a name="build"></a>
<h4>How do I build the Quartz source?</h4>
<p>Although Quartz ships "pre-built" many people like to make their own
alterations and/or build the latest 'non-released' version of Quartz from
CVS.  To do this, follow the instructions in the "README.TXT" file that
ships with Quartz.</p>

<hr /><!-- ----------------------------------------------------------------------- -->

<a name="scalability"></a>
<h4>How many jobs is Quartz capable of running?</h4>

<p>This is a tough question to answer... the answer is basically "it depends".</p>

<p>I know you hate that answer, to here's some information about what it depends
"on".</p>

<p>First off, the JobStore that you use plays a significant factor.  The
RAM-based JobStore is MUCH (1000x) faster than the JDBC-based JobStore.
The speed of JDBC-JobStore depends almost entirely on the speed of the connection
to your database, which data base system that you use, and what hardware the
database is running on.  Quartz actually does very little processing itself, nearly
all of the time is spent in the database.  Of course RAMJobStore has a more finite
limit on how many Jobs & Triggers can be stored, as you're sure to have less
RAM than hard-drive space for a database.  You may also look at the FAQ
"<a href="#jdbcjobstore">How do I improve the performance of JDBC-JobStore?</a>"</p>

<p>So, the limitting factor of the number of Triggers and Jobs Quartz can
"store" and monitor is really the amount of storage space available to
the JobStore (either the amount of RAM or the amount of disk space).</p>

<p>Now, aside from "how many can I store?" is the question of "how many jobs
can Quartz be running at the same moment in time?"</p>

<p>One thing that CAN slow down quartz itself is using a lot of listeners
(TriggerListeners, JobListeners, and SchedulerListeners).  The time spent in
each listener obviously adds into the time spent "processing" a job's execution,
outside of actual execution of the job.  This doesn't mean that you should be
terrified of using listeners, it just means that you should use them judiciously
- don't create a bunch of "global" listeners if you can really make more
specialized ones.  Also don't do "expensive" things in the listeners, unless
you really need to.  Also be mindful that many plug-ins (such as the "history"
plugin) are actually listeners.</p>

<p>The actual number of jobs that can be running at any moment in time is
limitted by the size of the thread pool.  If there are five threads in the pool,
no more than five jobs can run at a time.  Be careful of making a lot of threads
though, as the JVM, Operating System, and CPU all have a hard time juggling lots
of threads, and performance degrades just because of all of the management.  In
most cases performance starts to tank as you get into the hundreds of threads.
Be mindful that if you're running within an application server, it probably
has created at least a few dozen threads of its own!</p>

<p>Aside from those factors, <i><b>it really comes down to what your jobs DO</b></i>.  If
your jobs take a long time to complete their work, and/or their work is very
CPU-intensive, then you're obviously not going to be able to run very many
jobs at once, nor very many in a given spanse of time.</p>

<p>Finally, if you just can't get enough horse-power out of one Quartz instance,
you can always load-balance many Quartz instances (on separate machines).  Each
will run the jobs out of the shared database on a first-come first-serve basis,
as quickly as the triggers need fired.</p>

<p>So here you are this far into the answer of "how many", and I still haven't
given you a number ;-)   And I really hate to, because of all of the variables
mentioned above.  So let me just say, there are installments of Quartz out there
that are managing hundreds-of-thousands of Jobs and Triggers, and that at any
given moment in time are executing dozens of jobs -- and this excludes using
load-balancing.   With this in mind, most people should feel confident that
they can get the performance out of Quartz that they need.</p>

<hr /><!-- ----------------------------------------------------------------------- -->

<a name="rmi"></a>
<h4>I'm having issues with using Quartz via RMI -- HELP!?!</h4>

<p>RMI can be a bit problematic, especially if you don't have an understanding
of how class loading via RMI works.  I highly recommend reading all of the JavaDOC
available about RMI, and strongly suggest you read the following references,
dug up by a kind Quartz user (Mike Curwen)</p>


<p>An excellent description of RMI and codebase:
<a href="http://www.kedwards.com/jini/codebase.html">
http://www.kedwards.com/jini/codebase.html</a>.
One of the important points is to realize that "codebase" is used by the client!</p>

<p>Quick info about security managers:
<a href="http://gethelp.devx.com/techtips/java_pro/10MinuteSolutions/10min0500.asp">
http://gethelp.devx.com/techtips/java_pro/10MinuteSolutions/10min0500.asp</a>.</p>

<p>And finally from the java API docs, read the docs for the RMISecurityManager<br />
<a href="http://java.sun.com/j2se/1.3/docs/api/java/rmi/RMISecurityManager.html">
http://java.sun.com/j2se/1.3/docs/api/java/rmi/RMISecurityManager.html</a><br />
<br />
The important 'take away' of the API is: <br />
<br />
<table width="75%"><tr><td><div class="src">
<pre class="source">
RMI's class loader will not download any classes from
remote locations if no security manager has been set.
</pre>
</div>
</td></tr></table>
</p>

<hr /><!-- ----------------------------------------------------------------------- -->

<a name="durability"></a>
<h4>How do I keep a Job from being removed after it completes?</h4>

<p>Set the property <i>JobDetail.setDurability(true)</i> - which instructs
Quartz not to delete the Job when it becomes an "orphan" (when the Job not longer
has a Trigger referencing it).</p>

<hr /><!-- ----------------------------------------------------------------------- -->

<a name="statefulness"></a>
<h4>How do I keep a Job from firing concurrently?</h4>

<p>Make the job class implement <i>StatefulJob</i> rather than <i>Job</i>.
Read the JavaDOC for <i>StatefulJob</i> for more information.</p>

<hr /><!-- ----------------------------------------------------------------------- -->

<a name="abortJob"></a>
<h4>How do I stop a Job that is currently executing?</h4>

<p>
See the <i>org.quartz.InterruptableJob</i> interface, and the <i>Scheduler.interrupt(String, String)</i> method.</p>


<hr /><!-- ----------------------------------------------------------------------- -->

<a name="chaining"></a>
<h4>How do I chain Job execution? Or, how do I create a workflow?</h4>

<p>There currently is no "easy" or "free" way to chain triggers with
Quartz.  However there are several ways you can accomplish it, below is an
outline of a couple approaches:</p>

<p>One way is to use a listener (i.e. a <i>TriggerListener</i>, <i>JobListener</i>
or <i>SchedulerListener</i>) that can notice the completion of a job/trigger
and then immediately schedule a new trigger to fire.  This approach can get a
bit involved, since you'll have to inform the listener which job follows
which - and you may need to worry about persistence of this information.</p>

<p>Another way is to build a <i>Job</i> that contains within its
<i>JobDataMap</i> the name of the next job to fire, and as the job completes
(the last step in its execute() method) have the job schedule the next job.
Several people are doing this and have had good luck. Most have made a base
(abstract) class that is a Job that knows how to get the job name and group
out of the JobDataMap using special keys (constants) and contains code to
schedule the identified job.  Then they simply make extensions of this
class that included the additional work the job should do.</p>

<p>In the future, Quartz will provide a much cleaner way to do this, but
until then, you'll have to use one of the above approaches, or think
of yet another that works better for you.</p>

<hr /><!-- ----------------------------------------------------------------------- -->

<a name="notStarted"></a>
<h4>Why isn't my trigger firing?</h4>
<!-- ----------------------------------------------------------------------- -->
<p>The most common reason for this is not having called Scheduler.start(),
which tells the scheduler to start firing triggers.</p>

<hr /><!-- ----------------------------------------------------------------------- -->

<a name="jdbcjobstore"></a>
<h4>How do I improve the performance of JDBC-JobStore?</h4>

<p>There are a few known ways to speed up JDBC-JobStore, only one of which is
very practical.</p>

<p>First, the obvious, but not-so-practical:
<ul>
<li>Buy a better (faster) network between the machine that runs Quartz, and the machine that runs your RDBMS.</li>
<li>Buy a better (more powerful) machine to run your database on.</li>
<li>Buy a better RDBMS.</li>
</ul>
</p>
Now for something simple, but effective:  Build indexes on the Quartz tables.<br />
<br />
Most database systems will automatically put indexes on the primary-key fields,
many will also automatically do it for the foreign-key field.  Make sure yours
does this, or make the indexes on all key fields of every table manually.<br />
<br />
Next, manually add some additional indexes: most important to index are the
TRIGGER table's "next_fire_time" and "state" fields.  Last (but not as important),
add indexes to every column on the FIRED_TRIGGERS table.</p>


<pre class="source">
create index idx_qrtz_t_next_fire_time on qrtz_triggers(NEXT_FIRE_TIME);
create index idx_qrtz_t_state on qrtz_triggers(TRIGGER_STATE);
create index idx_qrtz_t_nf_st on qrtz_triggers(TRIGGER_STATE,NEXT_FIRE_TIME);
create index idx_qrtz_ft_trig_name on qrtz_fired_triggers(TRIGGER_NAME);
create index idx_qrtz_ft_trig_group on qrtz_fired_triggers(TRIGGER_GROUP);
create index idx_qrtz_ft_trig_name on qrtz_fired_triggers(TRIGGER_NAME);
create index idx_qrtz_ft_trig_n_g on qrtz_fired_triggers(TRIGGER_NAME,TRIGGER_GROUP);
create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(INSTANCE_NAME);
create index idx_qrtz_ft_job_name on qrtz_fired_triggers(JOB_NAME);
create index idx_qrtz_ft_job_group on qrtz_fired_triggers(JOB_GROUP);
</pre>

<hr /><!-- ----------------------------------------------------------------------- -->

<a name="connValidate"></a>
<h4>My DB Connections don't recover properly if the database server is restarted.</h4>
<!-- ----------------------------------------------------------------------- -->
<p>If you're having Quartz create the connection data source (by specifying the connection parameters in the quartz properties file) make sure you have a connection validation query specified, such as:
<pre class="source">
org.quartz.dataSource.myDS.validationQuery=select 0 from dual
</pre>
This particular query is extremly efficient for Oracle.  For other databases, you'll need to think of an efficient query that always works as long as the connection is good.
</p>

<p>If you're datasource is managed by your application server, make sure the datasource is configured in such a way that it can detect failed connections.</p>

<hr /><!-- ----------------------------------------------------------------------- -->

<a name="deadlocks"></a>
<h4>I'm using JobStoreCMT and I'm seeing deadlocks, what can I do?</h4>
<!-- ----------------------------------------------------------------------- -->
<p>JobStoreCMT is in heavy use, under heavy load by many people.  It is believed
to be free of bugs that can cause deadlock. However, every now and then we get 
complaints about deadlocks.  In all cases thus far, the problem has turned out
to be "user error", thus the list below is some things for you to check if
you are experiencing deadlocks.</p>

<ul>
  <li>Some databases falsely detect deadlocks when a tx takes a long time.  Make sure you have put indexes on your tables (see <a href="#jdbcjobstore">improving performance of JDBCJobStore</a>).</li>
  <li>Make sure you have at least number-of-threads-in-thread-pool + 2 connections in your datasources.</li>
  <li>Make sure you have both a managed and non-managed datasource configured for Quartz to use.</li>
  <li>Make sure that all work you do with the Scheduler interface is done from within a transaction.  Accomplish this by using the Scheduler within a SessionBean that has its tx settings "Required" and "Container".  Or within a MessageDrivenBean with similar settings. Finally, start a UserTransaction yourself, and commit the work when done.</li>
  <li>If your Jobs' execute() methods use the Scheduler, make sure a transaction is in progress by using a UserTransaction or by setting the Quartz config propery "org.quartz.scheduler.wrapJobExecutionInUserTransaction=true".</li>
</ul>

</body>
</html>