0
# Exception Handling
1
2
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.
3
4
## Capabilities
5
6
### Base Exception Classes
7
8
### SchedulerException
9
10
Base exception for all Quartz scheduler-related errors, providing the foundation for the exception hierarchy.
11
12
```java { .api }
13
/**
14
* Base exception for all Quartz scheduler errors
15
*/
16
class SchedulerException extends Exception {
17
/**
18
* Create exception with no message
19
*/
20
SchedulerException();
21
22
/**
23
* Create exception with message
24
* @param msg the error message
25
*/
26
SchedulerException(String msg);
27
28
/**
29
* Create exception wrapping another throwable
30
* @param cause the underlying cause
31
*/
32
SchedulerException(Throwable cause);
33
34
/**
35
* Create exception with message and underlying cause
36
* @param msg the error message
37
* @param cause the underlying cause
38
*/
39
SchedulerException(String msg, Throwable cause);
40
41
/**
42
* Get the underlying exception that caused this scheduler exception
43
* @return the wrapped exception or null
44
*/
45
Throwable getUnderlyingException();
46
47
/**
48
* Get string representation including underlying exception
49
* @return formatted string with full error details
50
*/
51
String toString();
52
}
53
```
54
55
### Job Execution Exceptions
56
57
### JobExecutionException
58
59
Exception thrown by job implementations to indicate execution problems and control trigger behavior.
60
61
```java { .api }
62
/**
63
* Exception thrown by Job implementations to indicate execution problems
64
* Provides control over trigger behavior after job failure
65
*/
66
class JobExecutionException extends SchedulerException {
67
/**
68
* Create exception with no special instructions
69
*/
70
JobExecutionException();
71
72
/**
73
* Create exception wrapping another throwable
74
* @param cause the underlying cause of job failure
75
*/
76
JobExecutionException(Throwable cause);
77
78
/**
79
* Create exception with message
80
* @param msg description of the job failure
81
*/
82
JobExecutionException(String msg);
83
84
/**
85
* Create exception with refire instruction
86
* @param refireImmediately if true, job will be re-executed immediately
87
*/
88
JobExecutionException(boolean refireImmediately);
89
90
/**
91
* Create exception with cause and refire instruction
92
* @param cause the underlying cause
93
* @param refireImmediately if true, job will be re-executed immediately
94
*/
95
JobExecutionException(Throwable cause, boolean refireImmediately);
96
97
/**
98
* Set whether the job should be re-executed immediately
99
* @param refire true to re-execute job immediately
100
*/
101
void setRefireImmediately(boolean refire);
102
103
/**
104
* Check if job should be re-executed immediately
105
* @return true if job should be refired immediately
106
*/
107
boolean refireImmediately();
108
109
/**
110
* Set whether the firing trigger should be unscheduled
111
* @param unscheduleTriggger true to unschedule the trigger that fired
112
*/
113
void setUnscheduleFiringTrigger(boolean unscheduleTriggger);
114
115
/**
116
* Check if the firing trigger should be unscheduled
117
* @return true if firing trigger should be unscheduled
118
*/
119
boolean unscheduleFiringTrigger();
120
121
/**
122
* Set whether all triggers for this job should be unscheduled
123
* @param unscheduleAllTriggers true to unschedule all job triggers
124
*/
125
void setUnscheduleAllTriggers(boolean unscheduleAllTriggers);
126
127
/**
128
* Check if all triggers for this job should be unscheduled
129
* @return true if all job triggers should be unscheduled
130
*/
131
boolean unscheduleAllTriggers();
132
}
133
```
134
135
**Usage Examples:**
136
137
```java
138
public class ResilientJob implements Job {
139
private static final int MAX_RETRIES = 3;
140
141
public void execute(JobExecutionContext context) throws JobExecutionException {
142
try {
143
performWork();
144
} catch (TransientException e) {
145
// Retry immediately for transient errors
146
int retryCount = context.getRefireCount();
147
if (retryCount < MAX_RETRIES) {
148
JobExecutionException jee = new JobExecutionException(
149
"Transient error, retrying (attempt " + (retryCount + 1) + ")", e);
150
jee.setRefireImmediately(true);
151
throw jee;
152
} else {
153
// Too many retries, unschedule this trigger
154
JobExecutionException jee = new JobExecutionException(
155
"Max retries exceeded, unscheduling trigger", e);
156
jee.setUnscheduleFiringTrigger(true);
157
throw jee;
158
}
159
} catch (PermanentException e) {
160
// Permanent error, unschedule all triggers for this job
161
JobExecutionException jee = new JobExecutionException(
162
"Permanent error, unscheduling all triggers", e);
163
jee.setUnscheduleAllTriggers(true);
164
throw jee;
165
} catch (Exception e) {
166
// Generic error, just fail this execution
167
throw new JobExecutionException("Job execution failed", e);
168
}
169
}
170
171
private void performWork() throws TransientException, PermanentException {
172
// Job implementation
173
}
174
}
175
```
176
177
### Persistence Exceptions
178
179
### JobPersistenceException
180
181
Exception indicating problems with job store persistence operations.
182
183
```java { .api }
184
/**
185
* Exception indicating job store persistence problems
186
*/
187
class JobPersistenceException extends SchedulerException {
188
/**
189
* Create persistence exception with no message
190
*/
191
JobPersistenceException();
192
193
/**
194
* Create persistence exception with message
195
* @param msg description of persistence problem
196
*/
197
JobPersistenceException(String msg);
198
199
/**
200
* Create persistence exception wrapping another throwable
201
* @param cause the underlying persistence error
202
*/
203
JobPersistenceException(Throwable cause);
204
205
/**
206
* Create persistence exception with message and cause
207
* @param msg description of persistence problem
208
* @param cause the underlying persistence error
209
*/
210
JobPersistenceException(String msg, Throwable cause);
211
}
212
```
213
214
### ObjectAlreadyExistsException
215
216
Exception thrown when attempting to store jobs, triggers, or calendars that already exist.
217
218
```java { .api }
219
/**
220
* Exception thrown when trying to store objects that already exist
221
*/
222
class ObjectAlreadyExistsException extends JobPersistenceException {
223
/**
224
* Create exception for generic object conflict
225
*/
226
ObjectAlreadyExistsException();
227
228
/**
229
* Create exception with custom message
230
* @param msg description of the conflict
231
*/
232
ObjectAlreadyExistsException(String msg);
233
234
/**
235
* Create exception for JobDetail conflict with auto-generated message
236
* @param jobDetail the conflicting job detail
237
*/
238
ObjectAlreadyExistsException(JobDetail jobDetail);
239
240
/**
241
* Create exception for Trigger conflict with auto-generated message
242
* @param trigger the conflicting trigger
243
*/
244
ObjectAlreadyExistsException(Trigger trigger);
245
}
246
```
247
248
**Usage Examples:**
249
250
```java
251
try {
252
// Try to add a job that might already exist
253
scheduler.addJob(jobDetail, false); // replace = false
254
} catch (ObjectAlreadyExistsException e) {
255
System.out.println("Job already exists: " + e.getMessage());
256
// Handle conflict - maybe update existing job instead
257
scheduler.addJob(jobDetail, true); // replace = true
258
} catch (JobPersistenceException e) {
259
System.err.println("Database error: " + e.getMessage());
260
// Handle persistence problems
261
} catch (SchedulerException e) {
262
System.err.println("Scheduler error: " + e.getMessage());
263
// Handle general scheduler problems
264
}
265
```
266
267
### Configuration Exceptions
268
269
### SchedulerConfigException
270
271
Exception indicating problems with scheduler configuration.
272
273
```java { .api }
274
/**
275
* Exception indicating scheduler configuration problems
276
*/
277
class SchedulerConfigException extends SchedulerException {
278
/**
279
* Create configuration exception with no message
280
*/
281
SchedulerConfigException();
282
283
/**
284
* Create configuration exception with message
285
* @param msg description of configuration problem
286
*/
287
SchedulerConfigException(String msg);
288
289
/**
290
* Create configuration exception wrapping another throwable
291
* @param cause the underlying configuration error
292
*/
293
SchedulerConfigException(Throwable cause);
294
295
/**
296
* Create configuration exception with message and cause
297
* @param msg description of configuration problem
298
* @param cause the underlying configuration error
299
*/
300
SchedulerConfigException(String msg, Throwable cause);
301
}
302
```
303
304
**Usage Examples:**
305
306
```java
307
try {
308
// Configure scheduler with properties
309
Properties props = new Properties();
310
props.setProperty("org.quartz.threadPool.class", "InvalidThreadPoolClass");
311
312
SchedulerFactory factory = new StdSchedulerFactory(props);
313
Scheduler scheduler = factory.getScheduler();
314
} catch (SchedulerConfigException e) {
315
System.err.println("Configuration error: " + e.getMessage());
316
// Handle configuration problems - maybe load default config
317
SchedulerFactory defaultFactory = new StdSchedulerFactory();
318
Scheduler scheduler = defaultFactory.getScheduler();
319
} catch (SchedulerException e) {
320
System.err.println("General scheduler error: " + e.getMessage());
321
}
322
```
323
324
### Job Interruption Exceptions
325
326
### UnableToInterruptJobException
327
328
Exception thrown when job interruption fails.
329
330
```java { .api }
331
/**
332
* Exception thrown when job interruption fails
333
*/
334
class UnableToInterruptJobException extends SchedulerException {
335
/**
336
* Create interruption exception with no message
337
*/
338
UnableToInterruptJobException();
339
340
/**
341
* Create interruption exception with message
342
* @param msg description of interruption problem
343
*/
344
UnableToInterruptJobException(String msg);
345
346
/**
347
* Create interruption exception wrapping another throwable
348
* @param cause the underlying interruption error
349
*/
350
UnableToInterruptJobException(Throwable cause);
351
352
/**
353
* Create interruption exception with message and cause
354
* @param msg description of interruption problem
355
* @param cause the underlying interruption error
356
*/
357
UnableToInterruptJobException(String msg, Throwable cause);
358
}
359
```
360
361
**Usage Examples:**
362
363
```java
364
try {
365
// Try to interrupt a running job
366
boolean interrupted = scheduler.interrupt(jobKey("longRunningJob"));
367
if (!interrupted) {
368
System.out.println("Job was not running");
369
}
370
} catch (UnableToInterruptJobException e) {
371
System.err.println("Could not interrupt job: " + e.getMessage());
372
// Handle interruption failure - maybe try shutdown instead
373
} catch (SchedulerException e) {
374
System.err.println("Scheduler error during interrupt: " + e.getMessage());
375
}
376
377
// Implementing interruptible job
378
public class InterruptibleJob implements InterruptableJob {
379
private volatile boolean interrupted = false;
380
381
public void execute(JobExecutionContext context) throws JobExecutionException {
382
for (int i = 0; i < 1000 && !interrupted; i++) {
383
// Do work in chunks, checking interrupt flag
384
processItem(i);
385
386
if (Thread.currentThread().isInterrupted()) {
387
interrupted = true;
388
throw new JobExecutionException("Job was interrupted");
389
}
390
}
391
}
392
393
public void interrupt() throws UnableToInterruptJobException {
394
this.interrupted = true;
395
// Additional cleanup if needed
396
try {
397
cleanup();
398
} catch (Exception e) {
399
throw new UnableToInterruptJobException("Cleanup failed during interrupt", e);
400
}
401
}
402
403
private void processItem(int item) {
404
// Process individual item
405
}
406
407
private void cleanup() {
408
// Cleanup resources
409
}
410
}
411
```
412
413
### Exception Handling Best Practices
414
415
### Error Handling Strategies
416
417
```java
418
// Comprehensive error handling in job implementation
419
public class RobustJob implements Job {
420
private static final Logger logger = LoggerFactory.getLogger(RobustJob.class);
421
422
public void execute(JobExecutionContext context) throws JobExecutionException {
423
String jobName = context.getJobDetail().getKey().getName();
424
425
try {
426
logger.info("Starting job: {}", jobName);
427
428
// Main job logic
429
performJobWork(context);
430
431
logger.info("Job completed successfully: {}", jobName);
432
433
} catch (RetryableException e) {
434
logger.warn("Retryable error in job {}: {}", jobName, e.getMessage());
435
handleRetryableError(context, e);
436
437
} catch (NonRetryableException e) {
438
logger.error("Non-retryable error in job {}: {}", jobName, e.getMessage(), e);
439
handleNonRetryableError(context, e);
440
441
} catch (Exception e) {
442
logger.error("Unexpected error in job {}: {}", jobName, e.getMessage(), e);
443
handleUnexpectedError(context, e);
444
}
445
}
446
447
private void handleRetryableError(JobExecutionContext context, Exception e)
448
throws JobExecutionException {
449
int maxRetries = context.getJobDetail().getJobDataMap().getIntValue("maxRetries");
450
int currentRetries = context.getRefireCount();
451
452
if (currentRetries < maxRetries) {
453
JobExecutionException jee = new JobExecutionException(e);
454
jee.setRefireImmediately(true);
455
throw jee;
456
} else {
457
JobExecutionException jee = new JobExecutionException("Max retries exceeded", e);
458
jee.setUnscheduleFiringTrigger(true);
459
throw jee;
460
}
461
}
462
463
private void handleNonRetryableError(JobExecutionContext context, Exception e)
464
throws JobExecutionException {
465
JobExecutionException jee = new JobExecutionException("Non-retryable error", e);
466
jee.setUnscheduleAllTriggers(true);
467
throw jee;
468
}
469
470
private void handleUnexpectedError(JobExecutionContext context, Exception e)
471
throws JobExecutionException {
472
// Log for investigation but don't unschedule
473
throw new JobExecutionException("Unexpected error occurred", e);
474
}
475
476
private void performJobWork(JobExecutionContext context)
477
throws RetryableException, NonRetryableException {
478
// Job implementation
479
}
480
}
481
482
// Exception handling in scheduler operations
483
public class SchedulerManager {
484
private static final Logger logger = LoggerFactory.getLogger(SchedulerManager.class);
485
486
public void scheduleJobSafely(JobDetail job, Trigger trigger) {
487
try {
488
scheduler.scheduleJob(job, trigger);
489
logger.info("Successfully scheduled job: {}", job.getKey());
490
491
} catch (ObjectAlreadyExistsException e) {
492
logger.warn("Job already exists, replacing: {}", job.getKey());
493
try {
494
scheduler.deleteJob(job.getKey());
495
scheduler.scheduleJob(job, trigger);
496
} catch (SchedulerException se) {
497
logger.error("Failed to replace existing job: {}", job.getKey(), se);
498
throw new RuntimeException("Could not schedule job", se);
499
}
500
501
} catch (SchedulerConfigException e) {
502
logger.error("Configuration error scheduling job: {}", job.getKey(), e);
503
throw new IllegalStateException("Scheduler misconfigured", e);
504
505
} catch (JobPersistenceException e) {
506
logger.error("Persistence error scheduling job: {}", job.getKey(), e);
507
// Maybe try with in-memory fallback
508
509
} catch (SchedulerException e) {
510
logger.error("General error scheduling job: {}", job.getKey(), e);
511
throw new RuntimeException("Could not schedule job", e);
512
}
513
}
514
}
515
```