or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

actuator-integration.mdauto-configuration.mdconfiguration-properties.mdindex.mdscheduler-customization.md

actuator-integration.mddocs/

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

```