0
# Actuator Integration
1
2
Management endpoints for monitoring and inspecting Quartz scheduler state, including jobs, triggers, and execution history. Provides both REST API and web interface for scheduler management through Spring Boot Actuator.
3
4
## Capabilities
5
6
### QuartzEndpoint
7
8
Main actuator endpoint that exposes Quartz scheduler information for monitoring and management.
9
10
```java { .api }
11
/**
12
* Actuator endpoint for exposing Quartz Scheduler information
13
* Available at /actuator/quartz when management endpoints are enabled
14
*/
15
@Endpoint(id = "quartz")
16
public class QuartzEndpoint {
17
18
/**
19
* Creates QuartzEndpoint with scheduler and sanitizing functions
20
* @param scheduler The Quartz Scheduler instance to monitor
21
* @param sanitizingFunctions Functions for sanitizing sensitive data in responses
22
*/
23
public QuartzEndpoint(Scheduler scheduler, Iterable<SanitizingFunction> sanitizingFunctions);
24
25
/**
26
* Return the available job and trigger group names
27
* @return QuartzDescriptor containing job and trigger group information
28
* @throws SchedulerException if retrieving information from scheduler fails
29
*/
30
@ReadOperation
31
public QuartzDescriptor quartzReport() throws SchedulerException;
32
33
/**
34
* Return available job names organized by group
35
* @return QuartzGroupsDescriptor containing job group details
36
* @throws SchedulerException if retrieving information from scheduler fails
37
*/
38
public QuartzGroupsDescriptor quartzJobGroups() throws SchedulerException;
39
40
/**
41
* Return available trigger names organized by group
42
* @return QuartzGroupsDescriptor containing trigger group details
43
* @throws SchedulerException if retrieving information from scheduler fails
44
*/
45
public QuartzGroupsDescriptor quartzTriggerGroups() throws SchedulerException;
46
47
/**
48
* Return job group summary with job details
49
* @param group The job group name
50
* @return QuartzJobGroupSummaryDescriptor containing jobs in the specified group
51
* @throws SchedulerException if retrieving information fails
52
*/
53
public QuartzJobGroupSummaryDescriptor quartzJobGroupSummary(String group) throws SchedulerException;
54
55
/**
56
* Return trigger group summary with trigger details
57
* @param group The trigger group name
58
* @return QuartzTriggerGroupSummaryDescriptor containing triggers in the specified group
59
* @throws SchedulerException if retrieving information fails
60
*/
61
public QuartzTriggerGroupSummaryDescriptor quartzTriggerGroupSummary(String group) throws SchedulerException;
62
63
/**
64
* Return detailed information about a specific job
65
* @param groupName Job group name
66
* @param jobName Job name
67
* @param showUnsanitized Whether to show unsanitized data
68
* @return QuartzJobDetailsDescriptor with detailed job information
69
* @throws SchedulerException if job cannot be found or accessed
70
*/
71
public QuartzJobDetailsDescriptor quartzJob(String groupName, String jobName, boolean showUnsanitized)
72
throws SchedulerException;
73
74
/**
75
* Return detailed information about a specific trigger
76
* @param groupName Trigger group name
77
* @param triggerName Trigger name
78
* @param showUnsanitized Whether to show unsanitized data
79
* @return Map containing detailed trigger information
80
* @throws SchedulerException if trigger cannot be found or accessed
81
*/
82
Map<String, Object> quartzTrigger(String groupName, String triggerName, boolean showUnsanitized)
83
throws SchedulerException;
84
85
/**
86
* Trigger a specific job to run immediately (write operation since Spring Boot 3.5.0)
87
* @param groupName Job group name
88
* @param jobName Job name
89
* @return QuartzJobTriggerDescriptor with trigger execution details
90
* @throws SchedulerException if job cannot be triggered
91
*/
92
@WriteOperation
93
public QuartzJobTriggerDescriptor triggerQuartzJob(String groupName, String jobName)
94
throws SchedulerException;
95
}
96
```
97
98
**Usage Examples:**
99
100
```bash
101
# Get overview of all job and trigger groups
102
curl http://localhost:8080/actuator/quartz
103
104
# Get all job groups
105
curl http://localhost:8080/actuator/quartz/jobs
106
107
# Get jobs in specific group
108
curl http://localhost:8080/actuator/quartz/jobs/myGroup
109
110
# Get specific job details
111
curl http://localhost:8080/actuator/quartz/jobs/myGroup/myJob
112
113
# Get all trigger groups
114
curl http://localhost:8080/actuator/quartz/triggers
115
116
# Get triggers in specific group
117
curl http://localhost:8080/actuator/quartz/triggers/myGroup
118
119
# Get specific trigger details
120
curl http://localhost:8080/actuator/quartz/triggers/myGroup/myTrigger
121
122
# Trigger a job to run immediately (write operation)
123
curl -X POST http://localhost:8080/actuator/quartz/jobs/myGroup/myJob \
124
-H "Content-Type: application/json" \
125
-d '{"state": "running"}'
126
```
127
128
### QuartzEndpointWebExtension
129
130
Web-specific extension providing additional HTTP operations for the Quartz endpoint with path variable support and enhanced security handling.
131
132
```java { .api }
133
/**
134
* Web extension for QuartzEndpoint providing additional HTTP-specific operations
135
* Adds path variable support and enhanced web interface capabilities
136
* Annotated with @EndpointWebExtension(endpoint = QuartzEndpoint.class)
137
*/
138
@EndpointWebExtension(endpoint = QuartzEndpoint.class)
139
public class QuartzEndpointWebExtension {
140
141
/**
142
* Creates web extension with endpoint and configuration
143
* @param endpoint The base QuartzEndpoint
144
* @param showValues Show configuration for sensitive data (ALWAYS, NEVER, WHEN_AUTHORIZED)
145
* @param roles Set of required roles for access
146
*/
147
public QuartzEndpointWebExtension(
148
QuartzEndpoint endpoint,
149
Show showValues,
150
Set<String> roles
151
);
152
153
/**
154
* Get jobs or triggers by group type via web interface
155
* @param jobsOrTriggers Either "jobs" or "triggers" path segment
156
* @return WebEndpointResponse with QuartzGroupsDescriptor
157
* @throws SchedulerException if group access fails
158
*/
159
@ReadOperation
160
public WebEndpointResponse<QuartzGroupsDescriptor> quartzJobOrTriggerGroups(@Selector String jobsOrTriggers)
161
throws SchedulerException;
162
163
/**
164
* Get specific job or trigger group summary via web interface
165
* @param jobsOrTriggers Either "jobs" or "triggers" path segment
166
* @param group Group name from path variable
167
* @return WebEndpointResponse with group summary
168
* @throws SchedulerException if group access fails
169
*/
170
@ReadOperation
171
public WebEndpointResponse<Object> quartzJobOrTriggerGroup(@Selector String jobsOrTriggers, @Selector String group)
172
throws SchedulerException;
173
174
/**
175
* Get specific job or trigger details via web interface
176
* @param securityContext Security context for access control
177
* @param jobsOrTriggers Either "jobs" or "triggers" path segment
178
* @param group Group name from path
179
* @param name Job or trigger name from path
180
* @return WebEndpointResponse with job or trigger details
181
* @throws SchedulerException if access fails
182
*/
183
@ReadOperation
184
public WebEndpointResponse<Object> quartzJobOrTrigger(SecurityContext securityContext,
185
@Selector String jobsOrTriggers, @Selector String group, @Selector String name)
186
throws SchedulerException;
187
188
/**
189
* Trigger a Quartz job via web interface (since Spring Boot 3.5.0)
190
* @param jobs Must be "jobs" path segment
191
* @param group Job group name from path
192
* @param name Job name from path
193
* @param state Desired state - must be "running" to trigger
194
* @return WebEndpointResponse indicating success or failure
195
* @throws SchedulerException if job triggering fails
196
*/
197
@WriteOperation
198
public WebEndpointResponse<Object> triggerQuartzJob(@Selector String jobs, @Selector String group,
199
@Selector String name, String state) throws SchedulerException;
200
}
201
```
202
203
### QuartzEndpointAutoConfiguration
204
205
Auto-configuration class that automatically sets up Quartz actuator endpoints when conditions are met.
206
207
```java { .api }
208
/**
209
* Auto-configuration for Quartz actuator endpoint
210
* Activates when Scheduler is available and endpoint is enabled
211
*/
212
@AutoConfiguration(after = QuartzAutoConfiguration.class)
213
@ConditionalOnClass(Scheduler.class)
214
@ConditionalOnAvailableEndpoint(QuartzEndpoint.class)
215
@EnableConfigurationProperties(QuartzEndpointProperties.class)
216
public class QuartzEndpointAutoConfiguration {
217
218
/**
219
* Creates QuartzEndpoint when Scheduler bean is available
220
* @param scheduler The Scheduler instance to monitor
221
* @param sanitizingFunctions Ordered stream of sanitizing functions
222
* @return Configured QuartzEndpoint
223
*/
224
@Bean
225
@ConditionalOnBean(Scheduler.class)
226
@ConditionalOnMissingBean
227
public QuartzEndpoint quartzEndpoint(
228
Scheduler scheduler,
229
ObjectProvider<SanitizingFunction> sanitizingFunctions
230
);
231
232
/**
233
* Creates web extension when web endpoints are enabled
234
* @param endpoint The base QuartzEndpoint
235
* @param properties Configuration properties for the endpoint
236
* @return Configured QuartzEndpointWebExtension
237
*/
238
@Bean
239
@ConditionalOnBean(QuartzEndpoint.class)
240
@ConditionalOnMissingBean
241
@ConditionalOnAvailableEndpoint(exposure = EndpointExposure.WEB)
242
public QuartzEndpointWebExtension quartzEndpointWebExtension(
243
QuartzEndpoint endpoint,
244
QuartzEndpointProperties properties
245
);
246
}
247
```
248
249
### QuartzEndpointProperties
250
251
Configuration properties for customizing the Quartz actuator endpoint behavior.
252
253
```java { .api }
254
/**
255
* Configuration properties for Quartz actuator endpoint
256
* Bound to management.endpoint.quartz configuration prefix
257
*/
258
@ConfigurationProperties("management.endpoint.quartz")
259
public class QuartzEndpointProperties {
260
261
/**
262
* Get the show configuration for sensitive data
263
* @return Show enum value (ALWAYS, NEVER, WHEN_AUTHORIZED - default: NEVER)
264
*/
265
public Show getShowValues();
266
267
/**
268
* Set the show configuration for sensitive data
269
* @param showValues Show configuration for endpoint data
270
*/
271
public void setShowValues(Show showValues);
272
273
/**
274
* Get list of required roles for endpoint access
275
* @return List of role names required for access (default: empty)
276
*/
277
public List<String> getRoles();
278
279
/**
280
* Set required roles for endpoint access
281
* @param roles List of role names that can access the endpoint
282
*/
283
public void setRoles(List<String> roles);
284
}
285
286
/**
287
* Enumeration for controlling when sensitive data should be shown in endpoint responses
288
*/
289
public enum Show {
290
/**
291
* Never show sensitive data values
292
*/
293
NEVER,
294
295
/**
296
* Show sensitive data values only when user is authorized
297
*/
298
WHEN_AUTHORIZED,
299
300
/**
301
* Always show sensitive data values
302
*/
303
ALWAYS
304
}
305
```
306
307
## Data Transfer Objects
308
309
The endpoint returns structured data through various descriptor classes:
310
311
```java { .api }
312
/**
313
* Root descriptor containing job and trigger group information
314
*/
315
public class QuartzDescriptor implements OperationResponseBody {
316
public QuartzDescriptor(GroupNamesDescriptor jobs, GroupNamesDescriptor triggers);
317
public GroupNamesDescriptor getJobs();
318
public GroupNamesDescriptor getTriggers();
319
}
320
321
/**
322
* Descriptor for group names
323
*/
324
public class GroupNamesDescriptor {
325
public GroupNamesDescriptor(Set<String> groups);
326
public Set<String> getGroups();
327
}
328
329
/**
330
* Descriptor for jobs organized by group
331
*/
332
public class QuartzGroupsDescriptor {
333
public Map<String, Object> getGroups();
334
}
335
336
/**
337
* Descriptor for job collection
338
*/
339
public class JobsDescriptor {
340
public Map<String, JobDescriptor> getJobs();
341
}
342
343
/**
344
* Descriptor for trigger collection
345
*/
346
public class TriggersDescriptor {
347
public Map<String, TriggerDescriptor> getTriggers();
348
}
349
350
/**
351
* Detailed job information descriptor
352
*/
353
public class JobDescriptor {
354
public String getGroup();
355
public String getName();
356
public String getDescription();
357
public String getClassName();
358
public boolean isDurable();
359
public boolean isRequestsRecovery();
360
public JobDataMapDescriptor getData();
361
}
362
363
/**
364
* Detailed trigger information descriptor
365
*/
366
public class TriggerDescriptor {
367
public String getGroup();
368
public String getName();
369
public String getDescription();
370
public String getState();
371
public String getType();
372
public String getCalendarName();
373
public Date getStartTime();
374
public Date getEndTime();
375
public Date getNextFireTime();
376
public Date getPreviousFireTime();
377
public int getPriority();
378
}
379
380
/**
381
* Job data map descriptor
382
*/
383
public class JobDataMapDescriptor {
384
public Map<String, Object> getData();
385
}
386
387
/**
388
* Job group summary descriptor
389
*/
390
public class QuartzJobGroupSummaryDescriptor {
391
public String getGroup();
392
public JobsDescriptor getJobs();
393
}
394
395
/**
396
* Trigger group summary descriptor
397
*/
398
public class QuartzTriggerGroupSummaryDescriptor {
399
public String getGroup();
400
public TriggersDescriptor getTriggers();
401
}
402
403
/**
404
* Job details descriptor with complete job information
405
*/
406
public class QuartzJobDetailsDescriptor {
407
public String getGroup();
408
public String getName();
409
public String getDescription();
410
public String getClassName();
411
public boolean isDurable();
412
public boolean isRequestsRecovery();
413
public JobDataMapDescriptor getData();
414
public List<TriggerDescriptor> getTriggers();
415
}
416
417
/**
418
* Job trigger descriptor for write operations
419
*/
420
public class QuartzJobTriggerDescriptor {
421
public String getGroup();
422
public String getName();
423
public Date getFireTime();
424
public String getState();
425
}
426
```
427
428
## Configuration Examples
429
430
### Basic Endpoint Configuration
431
432
```properties
433
# Enable Quartz endpoint
434
management.endpoints.web.exposure.include=quartz
435
management.endpoint.quartz.enabled=true
436
437
# Security configuration
438
management.endpoint.quartz.roles=ADMIN,OPERATOR
439
management.endpoint.quartz.show-values=password,secret
440
441
# Endpoint path customization
442
management.endpoints.web.path-mapping.quartz=scheduler
443
```
444
445
```yaml
446
management:
447
endpoints:
448
web:
449
exposure:
450
include: quartz,health,info
451
path-mapping:
452
quartz: scheduler
453
endpoint:
454
quartz:
455
enabled: true
456
roles:
457
- ADMIN
458
- OPERATOR
459
show-values:
460
- password
461
- apiKey
462
```
463
464
### Security Configuration
465
466
```java
467
@Configuration
468
@EnableWebSecurity
469
public class ActuatorSecurityConfiguration {
470
471
@Bean
472
public SecurityFilterChain actuatorFilterChain(HttpSecurity http) throws Exception {
473
return http
474
.requestMatcher(EndpointRequest.toAnyEndpoint())
475
.authorizeHttpRequests(requests -> requests
476
.requestMatchers(EndpointRequest.to(QuartzEndpoint.class))
477
.hasRole("ADMIN")
478
.anyRequest().hasRole("ACTUATOR")
479
)
480
.httpBasic(withDefaults())
481
.build();
482
}
483
}
484
```
485
486
### Custom Sanitizing Functions
487
488
```java
489
@Configuration
490
public class QuartzSanitizationConfiguration {
491
492
@Bean
493
public SanitizingFunction quartzDataSanitizer() {
494
return new SanitizingFunction() {
495
@Override
496
public SanitizableData apply(SanitizableData data) {
497
String key = data.getKey();
498
Object value = data.getValue();
499
500
if (key != null && key.toLowerCase().contains("password")) {
501
return data.withValue("******");
502
}
503
504
if (key != null && key.toLowerCase().contains("secret")) {
505
return data.withValue("[HIDDEN]");
506
}
507
508
return data;
509
}
510
};
511
}
512
}
513
```
514
515
## Monitoring and Alerting
516
517
### Custom Health Indicator
518
519
```java
520
@Component
521
public class QuartzHealthIndicator implements HealthIndicator {
522
523
private final Scheduler scheduler;
524
525
public QuartzHealthIndicator(Scheduler scheduler) {
526
this.scheduler = scheduler;
527
}
528
529
@Override
530
public Health health() {
531
try {
532
if (scheduler.isStarted()) {
533
int jobCount = scheduler.getJobKeys(GroupMatcher.anyGroup()).size();
534
int triggerCount = scheduler.getTriggerKeys(GroupMatcher.anyGroup()).size();
535
536
return Health.up()
537
.withDetail("jobs", jobCount)
538
.withDetail("triggers", triggerCount)
539
.withDetail("running", scheduler.getCurrentlyExecutingJobs().size())
540
.build();
541
} else {
542
return Health.down()
543
.withDetail("reason", "Scheduler is not started")
544
.build();
545
}
546
} catch (SchedulerException e) {
547
return Health.down(e)
548
.withDetail("error", e.getMessage())
549
.build();
550
}
551
}
552
}
553
```
554
555
### Metrics Integration
556
557
```java
558
@Configuration
559
public class QuartzMetricsConfiguration {
560
561
@Bean
562
public SchedulerFactoryBeanCustomizer metricsCustomizer(MeterRegistry meterRegistry) {
563
return schedulerFactoryBean -> {
564
schedulerFactoryBean.setGlobalJobListeners(
565
new MicrometerJobListener(meterRegistry)
566
);
567
};
568
}
569
}
570
571
public class MicrometerJobListener implements JobListener {
572
573
private final MeterRegistry meterRegistry;
574
private final Timer.Sample sample = Timer.start();
575
576
@Override
577
public void jobToBeExecuted(JobExecutionContext context) {
578
sample.start();
579
}
580
581
@Override
582
public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
583
sample.stop(Timer.builder("quartz.job.execution")
584
.tag("job", context.getJobDetail().getKey().toString())
585
.tag("success", jobException == null ? "true" : "false")
586
.register(meterRegistry));
587
}
588
}
589
```
590
591
## Error Handling
592
593
### Exception Management
594
595
```java
596
@ControllerAdvice
597
public class QuartzEndpointExceptionHandler {
598
599
@ExceptionHandler(SchedulerException.class)
600
public ResponseEntity<Map<String, String>> handleSchedulerException(SchedulerException e) {
601
Map<String, String> error = Map.of(
602
"error", "SchedulerException",
603
"message", e.getMessage(),
604
"timestamp", Instant.now().toString()
605
);
606
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
607
}
608
}
609
```
610
611
### Timeout Configuration
612
613
```properties
614
# Configure timeouts for endpoint operations
615
management.endpoint.quartz.cache.time-to-live=30s
616
server.servlet.context-timeout=60s
617
```