Quartz Enterprise Job Scheduler - A richly featured, open source job scheduling library that can be integrated within virtually any Java application
—
Comprehensive exception hierarchy for handling scheduling errors, job execution problems, and configuration issues in Quartz. The exception system provides detailed error information and allows for sophisticated error handling strategies.
Base exception for all Quartz scheduler-related errors, providing the foundation for the exception hierarchy.
/**
* Base exception for all Quartz scheduler errors
*/
class SchedulerException extends Exception {
/**
* Create exception with no message
*/
SchedulerException();
/**
* Create exception with message
* @param msg the error message
*/
SchedulerException(String msg);
/**
* Create exception wrapping another throwable
* @param cause the underlying cause
*/
SchedulerException(Throwable cause);
/**
* Create exception with message and underlying cause
* @param msg the error message
* @param cause the underlying cause
*/
SchedulerException(String msg, Throwable cause);
/**
* Get the underlying exception that caused this scheduler exception
* @return the wrapped exception or null
*/
Throwable getUnderlyingException();
/**
* Get string representation including underlying exception
* @return formatted string with full error details
*/
String toString();
}Exception thrown by job implementations to indicate execution problems and control trigger behavior.
/**
* Exception thrown by Job implementations to indicate execution problems
* Provides control over trigger behavior after job failure
*/
class JobExecutionException extends SchedulerException {
/**
* Create exception with no special instructions
*/
JobExecutionException();
/**
* Create exception wrapping another throwable
* @param cause the underlying cause of job failure
*/
JobExecutionException(Throwable cause);
/**
* Create exception with message
* @param msg description of the job failure
*/
JobExecutionException(String msg);
/**
* Create exception with refire instruction
* @param refireImmediately if true, job will be re-executed immediately
*/
JobExecutionException(boolean refireImmediately);
/**
* Create exception with cause and refire instruction
* @param cause the underlying cause
* @param refireImmediately if true, job will be re-executed immediately
*/
JobExecutionException(Throwable cause, boolean refireImmediately);
/**
* Set whether the job should be re-executed immediately
* @param refire true to re-execute job immediately
*/
void setRefireImmediately(boolean refire);
/**
* Check if job should be re-executed immediately
* @return true if job should be refired immediately
*/
boolean refireImmediately();
/**
* Set whether the firing trigger should be unscheduled
* @param unscheduleTriggger true to unschedule the trigger that fired
*/
void setUnscheduleFiringTrigger(boolean unscheduleTriggger);
/**
* Check if the firing trigger should be unscheduled
* @return true if firing trigger should be unscheduled
*/
boolean unscheduleFiringTrigger();
/**
* Set whether all triggers for this job should be unscheduled
* @param unscheduleAllTriggers true to unschedule all job triggers
*/
void setUnscheduleAllTriggers(boolean unscheduleAllTriggers);
/**
* Check if all triggers for this job should be unscheduled
* @return true if all job triggers should be unscheduled
*/
boolean unscheduleAllTriggers();
}Usage Examples:
public class ResilientJob implements Job {
private static final int MAX_RETRIES = 3;
public void execute(JobExecutionContext context) throws JobExecutionException {
try {
performWork();
} catch (TransientException e) {
// Retry immediately for transient errors
int retryCount = context.getRefireCount();
if (retryCount < MAX_RETRIES) {
JobExecutionException jee = new JobExecutionException(
"Transient error, retrying (attempt " + (retryCount + 1) + ")", e);
jee.setRefireImmediately(true);
throw jee;
} else {
// Too many retries, unschedule this trigger
JobExecutionException jee = new JobExecutionException(
"Max retries exceeded, unscheduling trigger", e);
jee.setUnscheduleFiringTrigger(true);
throw jee;
}
} catch (PermanentException e) {
// Permanent error, unschedule all triggers for this job
JobExecutionException jee = new JobExecutionException(
"Permanent error, unscheduling all triggers", e);
jee.setUnscheduleAllTriggers(true);
throw jee;
} catch (Exception e) {
// Generic error, just fail this execution
throw new JobExecutionException("Job execution failed", e);
}
}
private void performWork() throws TransientException, PermanentException {
// Job implementation
}
}Exception indicating problems with job store persistence operations.
/**
* Exception indicating job store persistence problems
*/
class JobPersistenceException extends SchedulerException {
/**
* Create persistence exception with no message
*/
JobPersistenceException();
/**
* Create persistence exception with message
* @param msg description of persistence problem
*/
JobPersistenceException(String msg);
/**
* Create persistence exception wrapping another throwable
* @param cause the underlying persistence error
*/
JobPersistenceException(Throwable cause);
/**
* Create persistence exception with message and cause
* @param msg description of persistence problem
* @param cause the underlying persistence error
*/
JobPersistenceException(String msg, Throwable cause);
}Exception thrown when attempting to store jobs, triggers, or calendars that already exist.
/**
* Exception thrown when trying to store objects that already exist
*/
class ObjectAlreadyExistsException extends JobPersistenceException {
/**
* Create exception for generic object conflict
*/
ObjectAlreadyExistsException();
/**
* Create exception with custom message
* @param msg description of the conflict
*/
ObjectAlreadyExistsException(String msg);
/**
* Create exception for JobDetail conflict with auto-generated message
* @param jobDetail the conflicting job detail
*/
ObjectAlreadyExistsException(JobDetail jobDetail);
/**
* Create exception for Trigger conflict with auto-generated message
* @param trigger the conflicting trigger
*/
ObjectAlreadyExistsException(Trigger trigger);
}Usage Examples:
try {
// Try to add a job that might already exist
scheduler.addJob(jobDetail, false); // replace = false
} catch (ObjectAlreadyExistsException e) {
System.out.println("Job already exists: " + e.getMessage());
// Handle conflict - maybe update existing job instead
scheduler.addJob(jobDetail, true); // replace = true
} catch (JobPersistenceException e) {
System.err.println("Database error: " + e.getMessage());
// Handle persistence problems
} catch (SchedulerException e) {
System.err.println("Scheduler error: " + e.getMessage());
// Handle general scheduler problems
}Exception indicating problems with scheduler configuration.
/**
* Exception indicating scheduler configuration problems
*/
class SchedulerConfigException extends SchedulerException {
/**
* Create configuration exception with no message
*/
SchedulerConfigException();
/**
* Create configuration exception with message
* @param msg description of configuration problem
*/
SchedulerConfigException(String msg);
/**
* Create configuration exception wrapping another throwable
* @param cause the underlying configuration error
*/
SchedulerConfigException(Throwable cause);
/**
* Create configuration exception with message and cause
* @param msg description of configuration problem
* @param cause the underlying configuration error
*/
SchedulerConfigException(String msg, Throwable cause);
}Usage Examples:
try {
// Configure scheduler with properties
Properties props = new Properties();
props.setProperty("org.quartz.threadPool.class", "InvalidThreadPoolClass");
SchedulerFactory factory = new StdSchedulerFactory(props);
Scheduler scheduler = factory.getScheduler();
} catch (SchedulerConfigException e) {
System.err.println("Configuration error: " + e.getMessage());
// Handle configuration problems - maybe load default config
SchedulerFactory defaultFactory = new StdSchedulerFactory();
Scheduler scheduler = defaultFactory.getScheduler();
} catch (SchedulerException e) {
System.err.println("General scheduler error: " + e.getMessage());
}Exception thrown when job interruption fails.
/**
* Exception thrown when job interruption fails
*/
class UnableToInterruptJobException extends SchedulerException {
/**
* Create interruption exception with no message
*/
UnableToInterruptJobException();
/**
* Create interruption exception with message
* @param msg description of interruption problem
*/
UnableToInterruptJobException(String msg);
/**
* Create interruption exception wrapping another throwable
* @param cause the underlying interruption error
*/
UnableToInterruptJobException(Throwable cause);
/**
* Create interruption exception with message and cause
* @param msg description of interruption problem
* @param cause the underlying interruption error
*/
UnableToInterruptJobException(String msg, Throwable cause);
}Usage Examples:
try {
// Try to interrupt a running job
boolean interrupted = scheduler.interrupt(jobKey("longRunningJob"));
if (!interrupted) {
System.out.println("Job was not running");
}
} catch (UnableToInterruptJobException e) {
System.err.println("Could not interrupt job: " + e.getMessage());
// Handle interruption failure - maybe try shutdown instead
} catch (SchedulerException e) {
System.err.println("Scheduler error during interrupt: " + e.getMessage());
}
// Implementing interruptible job
public class InterruptibleJob implements InterruptableJob {
private volatile boolean interrupted = false;
public void execute(JobExecutionContext context) throws JobExecutionException {
for (int i = 0; i < 1000 && !interrupted; i++) {
// Do work in chunks, checking interrupt flag
processItem(i);
if (Thread.currentThread().isInterrupted()) {
interrupted = true;
throw new JobExecutionException("Job was interrupted");
}
}
}
public void interrupt() throws UnableToInterruptJobException {
this.interrupted = true;
// Additional cleanup if needed
try {
cleanup();
} catch (Exception e) {
throw new UnableToInterruptJobException("Cleanup failed during interrupt", e);
}
}
private void processItem(int item) {
// Process individual item
}
private void cleanup() {
// Cleanup resources
}
}// Comprehensive error handling in job implementation
public class RobustJob implements Job {
private static final Logger logger = LoggerFactory.getLogger(RobustJob.class);
public void execute(JobExecutionContext context) throws JobExecutionException {
String jobName = context.getJobDetail().getKey().getName();
try {
logger.info("Starting job: {}", jobName);
// Main job logic
performJobWork(context);
logger.info("Job completed successfully: {}", jobName);
} catch (RetryableException e) {
logger.warn("Retryable error in job {}: {}", jobName, e.getMessage());
handleRetryableError(context, e);
} catch (NonRetryableException e) {
logger.error("Non-retryable error in job {}: {}", jobName, e.getMessage(), e);
handleNonRetryableError(context, e);
} catch (Exception e) {
logger.error("Unexpected error in job {}: {}", jobName, e.getMessage(), e);
handleUnexpectedError(context, e);
}
}
private void handleRetryableError(JobExecutionContext context, Exception e)
throws JobExecutionException {
int maxRetries = context.getJobDetail().getJobDataMap().getIntValue("maxRetries");
int currentRetries = context.getRefireCount();
if (currentRetries < maxRetries) {
JobExecutionException jee = new JobExecutionException(e);
jee.setRefireImmediately(true);
throw jee;
} else {
JobExecutionException jee = new JobExecutionException("Max retries exceeded", e);
jee.setUnscheduleFiringTrigger(true);
throw jee;
}
}
private void handleNonRetryableError(JobExecutionContext context, Exception e)
throws JobExecutionException {
JobExecutionException jee = new JobExecutionException("Non-retryable error", e);
jee.setUnscheduleAllTriggers(true);
throw jee;
}
private void handleUnexpectedError(JobExecutionContext context, Exception e)
throws JobExecutionException {
// Log for investigation but don't unschedule
throw new JobExecutionException("Unexpected error occurred", e);
}
private void performJobWork(JobExecutionContext context)
throws RetryableException, NonRetryableException {
// Job implementation
}
}
// Exception handling in scheduler operations
public class SchedulerManager {
private static final Logger logger = LoggerFactory.getLogger(SchedulerManager.class);
public void scheduleJobSafely(JobDetail job, Trigger trigger) {
try {
scheduler.scheduleJob(job, trigger);
logger.info("Successfully scheduled job: {}", job.getKey());
} catch (ObjectAlreadyExistsException e) {
logger.warn("Job already exists, replacing: {}", job.getKey());
try {
scheduler.deleteJob(job.getKey());
scheduler.scheduleJob(job, trigger);
} catch (SchedulerException se) {
logger.error("Failed to replace existing job: {}", job.getKey(), se);
throw new RuntimeException("Could not schedule job", se);
}
} catch (SchedulerConfigException e) {
logger.error("Configuration error scheduling job: {}", job.getKey(), e);
throw new IllegalStateException("Scheduler misconfigured", e);
} catch (JobPersistenceException e) {
logger.error("Persistence error scheduling job: {}", job.getKey(), e);
// Maybe try with in-memory fallback
} catch (SchedulerException e) {
logger.error("General error scheduling job: {}", job.getKey(), e);
throw new RuntimeException("Could not schedule job", e);
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-quartz-scheduler--quartz