or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

calendar-management.mdcore-scheduling.mdenterprise-features.mdexception-handling.mdindex.mdjob-management.mdlisteners-events.mdmatcher-framework.mdpersistence-storage.mdschedule-builders.mdtrigger-management.mdutilities-helpers.md

listeners-events.mddocs/

0

# Listeners and Events

1

2

Event-driven architecture for monitoring job executions, trigger firings, and scheduler lifecycle events in Quartz. The listener framework provides comprehensive hooks for observing and responding to scheduler activities.

3

4

## Capabilities

5

6

### Job Listeners

7

8

### JobListener Interface

9

10

Interface for receiving notifications about job execution lifecycle events.

11

12

```java { .api }

13

/**

14

* Interface for receiving notifications about job executions

15

*/

16

interface JobListener {

17

/**

18

* Get the unique name of this listener

19

* @return listener name for identification and management

20

*/

21

String getName();

22

23

/**

24

* Called just before a job is executed

25

* @param context the job execution context

26

*/

27

void jobToBeExecuted(JobExecutionContext context);

28

29

/**

30

* Called when job execution is vetoed by a TriggerListener

31

* @param context the job execution context

32

*/

33

void jobExecutionVetoed(JobExecutionContext context);

34

35

/**

36

* Called after a job has been executed (successfully or with exception)

37

* @param context the job execution context

38

* @param jobException the exception thrown by job (null if successful)

39

*/

40

void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException);

41

}

42

```

43

44

**Usage Examples:**

45

46

```java

47

// Basic job listener implementation

48

public class BasicJobListener implements JobListener {

49

private static final Logger logger = LoggerFactory.getLogger(BasicJobListener.class);

50

51

public String getName() {

52

return "BasicJobListener";

53

}

54

55

public void jobToBeExecuted(JobExecutionContext context) {

56

JobKey jobKey = context.getJobDetail().getKey();

57

logger.info("Job about to execute: {}", jobKey);

58

59

// Record start time in context for duration calculation

60

context.put("startTime", System.currentTimeMillis());

61

}

62

63

public void jobExecutionVetoed(JobExecutionContext context) {

64

JobKey jobKey = context.getJobDetail().getKey();

65

logger.warn("Job execution vetoed: {}", jobKey);

66

}

67

68

public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {

69

JobKey jobKey = context.getJobDetail().getKey();

70

71

if (jobException == null) {

72

// Calculate execution time

73

Long startTime = (Long) context.get("startTime");

74

long duration = System.currentTimeMillis() - startTime;

75

logger.info("Job completed successfully: {} ({}ms)", jobKey, duration);

76

} else {

77

logger.error("Job failed: {} - {}", jobKey, jobException.getMessage());

78

79

// Handle specific job exception instructions

80

if (jobException.refireImmediately()) {

81

logger.info("Job will be refired immediately");

82

}

83

if (jobException.unscheduleFiringTrigger()) {

84

logger.warn("Firing trigger will be unscheduled");

85

}

86

if (jobException.unscheduleAllTriggers()) {

87

logger.error("All triggers for job will be unscheduled");

88

}

89

}

90

}

91

}

92

93

// Performance monitoring job listener

94

public class PerformanceJobListener implements JobListener {

95

private final Map<String, Long> executionTimes = new ConcurrentHashMap<>();

96

97

public String getName() {

98

return "PerformanceJobListener";

99

}

100

101

public void jobToBeExecuted(JobExecutionContext context) {

102

String fireInstanceId = context.getFireInstanceId();

103

executionTimes.put(fireInstanceId, System.currentTimeMillis());

104

}

105

106

public void jobExecutionVetoed(JobExecutionContext context) {

107

String fireInstanceId = context.getFireInstanceId();

108

executionTimes.remove(fireInstanceId);

109

}

110

111

public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {

112

String fireInstanceId = context.getFireInstanceId();

113

Long startTime = executionTimes.remove(fireInstanceId);

114

115

if (startTime != null) {

116

long duration = System.currentTimeMillis() - startTime;

117

JobKey jobKey = context.getJobDetail().getKey();

118

119

// Log performance metrics

120

System.out.printf("Job %s executed in %d ms%n", jobKey, duration);

121

122

// Alert on slow jobs

123

if (duration > 30000) { // 30 seconds

124

System.err.printf("SLOW JOB ALERT: %s took %d ms%n", jobKey, duration);

125

}

126

}

127

}

128

}

129

```

130

131

### Trigger Listeners

132

133

### TriggerListener Interface

134

135

Interface for receiving notifications about trigger firing events and controlling job execution.

136

137

```java { .api }

138

/**

139

* Interface for receiving notifications about trigger firings

140

*/

141

interface TriggerListener {

142

/**

143

* Get the unique name of this listener

144

* @return listener name for identification and management

145

*/

146

String getName();

147

148

/**

149

* Called when a trigger fires (before job execution)

150

* @param trigger the trigger that fired

151

* @param context the job execution context

152

*/

153

void triggerFired(Trigger trigger, JobExecutionContext context);

154

155

/**

156

* Called to determine if job execution should be vetoed

157

* This method can prevent job execution after trigger fires

158

* @param trigger the trigger that fired

159

* @param context the job execution context

160

* @return true to veto job execution, false to allow it

161

*/

162

boolean vetoJobExecution(Trigger trigger, JobExecutionContext context);

163

164

/**

165

* Called when a trigger misfires

166

* @param trigger the trigger that misfired

167

*/

168

void triggerMisfired(Trigger trigger);

169

170

/**

171

* Called when trigger execution is complete

172

* @param trigger the trigger that completed

173

* @param context the job execution context

174

* @param triggerInstructionCode instruction for what to do next

175

*/

176

void triggerComplete(Trigger trigger, JobExecutionContext context,

177

CompletedExecutionInstruction triggerInstructionCode);

178

}

179

```

180

181

**Usage Examples:**

182

183

```java

184

// Basic trigger listener

185

public class BasicTriggerListener implements TriggerListener {

186

private static final Logger logger = LoggerFactory.getLogger(BasicTriggerListener.class);

187

188

public String getName() {

189

return "BasicTriggerListener";

190

}

191

192

public void triggerFired(Trigger trigger, JobExecutionContext context) {

193

logger.info("Trigger fired: {} for job: {}",

194

trigger.getKey(), context.getJobDetail().getKey());

195

}

196

197

public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {

198

// Example: veto execution during maintenance window

199

Calendar now = Calendar.getInstance();

200

int hour = now.get(Calendar.HOUR_OF_DAY);

201

202

if (hour >= 2 && hour <= 4) { // 2 AM - 4 AM maintenance window

203

logger.warn("Vetoing job execution during maintenance window: {}",

204

context.getJobDetail().getKey());

205

return true;

206

}

207

208

return false; // Allow execution

209

}

210

211

public void triggerMisfired(Trigger trigger) {

212

logger.warn("Trigger misfired: {}", trigger.getKey());

213

}

214

215

public void triggerComplete(Trigger trigger, JobExecutionContext context,

216

CompletedExecutionInstruction triggerInstructionCode) {

217

logger.info("Trigger completed: {} with instruction: {}",

218

trigger.getKey(), triggerInstructionCode);

219

220

// Handle completion instructions

221

switch (triggerInstructionCode) {

222

case DELETE_TRIGGER:

223

logger.info("Trigger will be deleted");

224

break;

225

case SET_TRIGGER_COMPLETE:

226

logger.info("Trigger marked as complete");

227

break;

228

case RE_EXECUTE_JOB:

229

logger.info("Job will be re-executed");

230

break;

231

}

232

}

233

}

234

235

// Load balancing trigger listener

236

public class LoadBalancingTriggerListener implements TriggerListener {

237

private final AtomicInteger activeJobs = new AtomicInteger(0);

238

private final int maxConcurrentJobs;

239

240

public LoadBalancingTriggerListener(int maxConcurrentJobs) {

241

this.maxConcurrentJobs = maxConcurrentJobs;

242

}

243

244

public String getName() {

245

return "LoadBalancingTriggerListener";

246

}

247

248

public void triggerFired(Trigger trigger, JobExecutionContext context) {

249

// Track trigger firing

250

}

251

252

public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {

253

int currentActive = activeJobs.get();

254

if (currentActive >= maxConcurrentJobs) {

255

System.out.printf("Vetoing job execution - too many active jobs (%d/%d)%n",

256

currentActive, maxConcurrentJobs);

257

return true;

258

}

259

260

activeJobs.incrementAndGet();

261

return false;

262

}

263

264

public void triggerMisfired(Trigger trigger) {

265

// Handle misfires

266

}

267

268

public void triggerComplete(Trigger trigger, JobExecutionContext context,

269

CompletedExecutionInstruction triggerInstructionCode) {

270

activeJobs.decrementAndGet();

271

}

272

}

273

```

274

275

### Scheduler Listeners

276

277

### SchedulerListener Interface

278

279

Interface for receiving notifications about scheduler lifecycle and management events.

280

281

```java { .api }

282

/**

283

* Interface for receiving notifications about scheduler events

284

*/

285

interface SchedulerListener {

286

/**

287

* Called when a job is scheduled

288

* @param trigger the trigger that was scheduled

289

*/

290

void jobScheduled(Trigger trigger);

291

292

/**

293

* Called when a job is unscheduled

294

* @param triggerKey the key of the unscheduled trigger

295

*/

296

void jobUnscheduled(TriggerKey triggerKey);

297

298

/**

299

* Called when a trigger is finalized (will not fire again)

300

* @param trigger the finalized trigger

301

*/

302

void triggerFinalized(Trigger trigger);

303

304

/**

305

* Called when a trigger is paused

306

* @param triggerKey the key of the paused trigger

307

*/

308

void triggerPaused(TriggerKey triggerKey);

309

310

/**

311

* Called when a group of triggers is paused

312

* @param triggerGroup the name of the paused trigger group

313

*/

314

void triggersPaused(String triggerGroup);

315

316

/**

317

* Called when a trigger is resumed

318

* @param triggerKey the key of the resumed trigger

319

*/

320

void triggerResumed(TriggerKey triggerKey);

321

322

/**

323

* Called when a group of triggers is resumed

324

* @param triggerGroup the name of the resumed trigger group

325

*/

326

void triggersResumed(String triggerGroup);

327

328

/**

329

* Called when a job is added to the scheduler

330

* @param jobDetail the added job

331

*/

332

void jobAdded(JobDetail jobDetail);

333

334

/**

335

* Called when a job is deleted from the scheduler

336

* @param jobKey the key of the deleted job

337

*/

338

void jobDeleted(JobKey jobKey);

339

340

/**

341

* Called when a job is paused

342

* @param jobKey the key of the paused job

343

*/

344

void jobPaused(JobKey jobKey);

345

346

/**

347

* Called when a group of jobs is paused

348

* @param jobGroup the name of the paused job group

349

*/

350

void jobsPaused(String jobGroup);

351

352

/**

353

* Called when a job is resumed

354

* @param jobKey the key of the resumed job

355

*/

356

void jobResumed(JobKey jobKey);

357

358

/**

359

* Called when a group of jobs is resumed

360

* @param jobGroup the name of the resumed job group

361

*/

362

void jobsResumed(String jobGroup);

363

364

/**

365

* Called when a scheduler error occurs

366

* @param msg error message

367

* @param cause the scheduler exception that occurred

368

*/

369

void schedulerError(String msg, SchedulerException cause);

370

371

/**

372

* Called when the scheduler is put in standby mode

373

*/

374

void schedulerInStandbyMode();

375

376

/**

377

* Called when the scheduler is started

378

*/

379

void schedulerStarted();

380

381

/**

382

* Called when the scheduler is starting

383

*/

384

void schedulerStarting();

385

386

/**

387

* Called when the scheduler is shutdown

388

*/

389

void schedulerShutdown();

390

391

/**

392

* Called when the scheduler is shutting down

393

*/

394

void schedulerShuttingdown();

395

396

/**

397

* Called when scheduling data is cleared

398

*/

399

void schedulingDataCleared();

400

}

401

```

402

403

**Usage Examples:**

404

405

```java

406

// Comprehensive scheduler listener

407

public class MonitoringSchedulerListener implements SchedulerListener {

408

private static final Logger logger = LoggerFactory.getLogger(MonitoringSchedulerListener.class);

409

410

// Job lifecycle events

411

public void jobScheduled(Trigger trigger) {

412

logger.info("Job scheduled: {} with trigger: {}",

413

trigger.getJobKey(), trigger.getKey());

414

}

415

416

public void jobUnscheduled(TriggerKey triggerKey) {

417

logger.info("Job unscheduled via trigger: {}", triggerKey);

418

}

419

420

public void jobAdded(JobDetail jobDetail) {

421

logger.info("Job added: {} (durable: {})",

422

jobDetail.getKey(), jobDetail.isDurable());

423

}

424

425

public void jobDeleted(JobKey jobKey) {

426

logger.info("Job deleted: {}", jobKey);

427

}

428

429

// Job state management events

430

public void jobPaused(JobKey jobKey) {

431

logger.info("Job paused: {}", jobKey);

432

}

433

434

public void jobsPaused(String jobGroup) {

435

logger.info("Jobs paused in group: {}", jobGroup);

436

}

437

438

public void jobResumed(JobKey jobKey) {

439

logger.info("Job resumed: {}", jobKey);

440

}

441

442

public void jobsResumed(String jobGroup) {

443

logger.info("Jobs resumed in group: {}", jobGroup);

444

}

445

446

// Trigger state management events

447

public void triggerPaused(TriggerKey triggerKey) {

448

logger.info("Trigger paused: {}", triggerKey);

449

}

450

451

public void triggersPaused(String triggerGroup) {

452

logger.info("Triggers paused in group: {}", triggerGroup);

453

}

454

455

public void triggerResumed(TriggerKey triggerKey) {

456

logger.info("Trigger resumed: {}", triggerKey);

457

}

458

459

public void triggersResumed(String triggerGroup) {

460

logger.info("Triggers resumed in group: {}", triggerGroup);

461

}

462

463

public void triggerFinalized(Trigger trigger) {

464

logger.info("Trigger finalized (will not fire again): {}", trigger.getKey());

465

}

466

467

// Scheduler lifecycle events

468

public void schedulerStarting() {

469

logger.info("Scheduler is starting...");

470

}

471

472

public void schedulerStarted() {

473

logger.info("Scheduler started successfully");

474

}

475

476

public void schedulerInStandbyMode() {

477

logger.info("Scheduler is in standby mode");

478

}

479

480

public void schedulerShuttingdown() {

481

logger.info("Scheduler is shutting down...");

482

}

483

484

public void schedulerShutdown() {

485

logger.info("Scheduler has been shutdown");

486

}

487

488

public void schedulingDataCleared() {

489

logger.warn("All scheduling data has been cleared");

490

}

491

492

// Error handling

493

public void schedulerError(String msg, SchedulerException cause) {

494

logger.error("Scheduler error: {} - {}", msg, cause.getMessage(), cause);

495

496

// Could implement alerting, recovery logic, etc.

497

if (cause instanceof JobPersistenceException) {

498

logger.error("Database persistence error detected");

499

}

500

}

501

}

502

503

// Statistics collecting scheduler listener

504

public class StatisticsSchedulerListener implements SchedulerListener {

505

private final AtomicInteger jobsScheduled = new AtomicInteger(0);

506

private final AtomicInteger jobsUnscheduled = new AtomicInteger(0);

507

private final AtomicInteger errors = new AtomicInteger(0);

508

private volatile boolean schedulerRunning = false;

509

510

public void jobScheduled(Trigger trigger) {

511

jobsScheduled.incrementAndGet();

512

}

513

514

public void jobUnscheduled(TriggerKey triggerKey) {

515

jobsUnscheduled.incrementAndGet();

516

}

517

518

public void schedulerStarted() {

519

schedulerRunning = true;

520

}

521

522

public void schedulerShutdown() {

523

schedulerRunning = false;

524

}

525

526

public void schedulerError(String msg, SchedulerException cause) {

527

errors.incrementAndGet();

528

}

529

530

// Getters for statistics

531

public int getJobsScheduled() { return jobsScheduled.get(); }

532

public int getJobsUnscheduled() { return jobsUnscheduled.get(); }

533

public int getErrors() { return errors.get(); }

534

public boolean isSchedulerRunning() { return schedulerRunning; }

535

536

// Other methods with empty implementations

537

public void jobAdded(JobDetail jobDetail) {}

538

public void jobDeleted(JobKey jobKey) {}

539

// ... etc

540

}

541

```

542

543

### Listener Management

544

545

### ListenerManager Interface

546

547

Interface for managing listener registration and matcher-based filtering.

548

549

```java { .api }

550

/**

551

* Interface for managing listeners with matcher-based filtering

552

*/

553

interface ListenerManager {

554

// Job listener management

555

void addJobListener(JobListener jobListener);

556

void addJobListener(JobListener jobListener, Matcher<JobKey> matcher);

557

void addJobListener(JobListener jobListener, Matcher<JobKey>... matchers);

558

void addJobListener(JobListener jobListener, List<Matcher<JobKey>> matchers);

559

boolean addJobListenerMatcher(String listenerName, Matcher<JobKey> matcher);

560

boolean removeJobListenerMatcher(String listenerName, Matcher<JobKey> matcher);

561

Set<Matcher<JobKey>> getJobListenerMatchers(String listenerName);

562

boolean setJobListenerMatchers(String listenerName, List<Matcher<JobKey>> matchers);

563

boolean removeJobListener(String name);

564

List<JobListener> getJobListeners();

565

JobListener getJobListener(String name);

566

567

// Trigger listener management

568

void addTriggerListener(TriggerListener triggerListener);

569

void addTriggerListener(TriggerListener triggerListener, Matcher<TriggerKey> matcher);

570

void addTriggerListener(TriggerListener triggerListener, Matcher<TriggerKey>... matchers);

571

void addTriggerListener(TriggerListener triggerListener, List<Matcher<TriggerKey>> matchers);

572

boolean addTriggerListenerMatcher(String listenerName, Matcher<TriggerKey> matcher);

573

boolean removeTriggerListenerMatcher(String listenerName, Matcher<TriggerKey> matcher);

574

Set<Matcher<TriggerKey>> getTriggerListenerMatchers(String listenerName);

575

boolean setTriggerListenerMatchers(String listenerName, List<Matcher<TriggerKey>> matchers);

576

boolean removeTriggerListener(String name);

577

List<TriggerListener> getTriggerListeners();

578

TriggerListener getTriggerListener(String name);

579

580

// Scheduler listener management

581

void addSchedulerListener(SchedulerListener schedulerListener);

582

boolean removeSchedulerListener(SchedulerListener schedulerListener);

583

List<SchedulerListener> getSchedulerListeners();

584

}

585

```

586

587

**Usage Examples:**

588

589

```java

590

// Register listeners with the scheduler

591

Scheduler scheduler = new StdSchedulerFactory().getScheduler();

592

ListenerManager listenerManager = scheduler.getListenerManager();

593

594

// Add job listeners

595

JobListener performanceListener = new PerformanceJobListener();

596

JobListener loggingListener = new BasicJobListener();

597

598

// Global job listener (listens to all jobs)

599

listenerManager.addJobListener(loggingListener);

600

601

// Job listener with specific matcher (only "report" group jobs)

602

listenerManager.addJobListener(performanceListener,

603

GroupMatcher.jobGroupEquals("reports"));

604

605

// Job listener with multiple matchers

606

listenerManager.addJobListener(performanceListener,

607

GroupMatcher.jobGroupEquals("reports"),

608

GroupMatcher.jobGroupEquals("analytics"));

609

610

// Add trigger listeners

611

TriggerListener loadBalancer = new LoadBalancingTriggerListener(5);

612

TriggerListener basicTriggerListener = new BasicTriggerListener();

613

614

// Global trigger listener

615

listenerManager.addTriggerListener(basicTriggerListener);

616

617

// Trigger listener for specific group

618

listenerManager.addTriggerListener(loadBalancer,

619

GroupMatcher.triggerGroupEquals("batch"));

620

621

// Add scheduler listeners

622

SchedulerListener monitoringListener = new MonitoringSchedulerListener();

623

SchedulerListener statsListener = new StatisticsSchedulerListener();

624

625

listenerManager.addSchedulerListener(monitoringListener);

626

listenerManager.addSchedulerListener(statsListener);

627

628

// Managing listener matchers

629

String listenerName = performanceListener.getName();

630

631

// Add additional matcher to existing listener

632

listenerManager.addJobListenerMatcher(listenerName,

633

KeyMatcher.keyEquals(jobKey("importantJob", "critical")));

634

635

// Replace all matchers for a listener

636

List<Matcher<JobKey>> newMatchers = Arrays.asList(

637

GroupMatcher.jobGroupEquals("highPriority"),

638

GroupMatcher.jobGroupContains("urgent")

639

);

640

listenerManager.setJobListenerMatchers(listenerName, newMatchers);

641

642

// Remove specific matcher

643

listenerManager.removeJobListenerMatcher(listenerName,

644

GroupMatcher.jobGroupEquals("reports"));

645

646

// Remove listeners

647

listenerManager.removeJobListener(performanceListener.getName());

648

listenerManager.removeTriggerListener(loadBalancer.getName());

649

listenerManager.removeSchedulerListener(statsListener);

650

```

651

652

### Matcher Classes

653

654

Utility classes for matching jobs and triggers in listener registration.

655

656

```java { .api }

657

/**

658

* Matchers for filtering which jobs/triggers listeners should monitor

659

*/

660

class GroupMatcher<T extends Key<T>> {

661

static <T extends Key<T>> GroupMatcher<T> groupEquals(String group);

662

static <T extends Key<T>> GroupMatcher<T> groupStartsWith(String prefix);

663

static <T extends Key<T>> GroupMatcher<T> groupEndsWith(String suffix);

664

static <T extends Key<T>> GroupMatcher<T> groupContains(String substring);

665

static <T extends Key<T>> GroupMatcher<T> anyGroup();

666

}

667

668

class KeyMatcher<T extends Key<T>> {

669

static <T extends Key<T>> KeyMatcher<T> keyEquals(T key);

670

}

671

672

class NameMatcher<T extends Key<T>> {

673

static <T extends Key<T>> NameMatcher<T> nameEquals(String name);

674

static <T extends Key<T>> NameMatcher<T> nameStartsWith(String prefix);

675

static <T extends Key<T>> NameMatcher<T> nameEndsWith(String suffix);

676

static <T extends Key<T>> NameMatcher<T> nameContains(String substring);

677

}

678

679

class AndMatcher<T extends Key<T>> {

680

static <T extends Key<T>> AndMatcher<T> and(Matcher<T>... matchers);

681

}

682

683

class OrMatcher<T extends Key<T>> {

684

static <T extends Key<T>> OrMatcher<T> or(Matcher<T>... matchers);

685

}

686

687

class NotMatcher<T extends Key<T>> {

688

static <T extends Key<T>> NotMatcher<T> not(Matcher<T> matcher);

689

}

690

```

691

692

**Usage Examples:**

693

694

```java

695

// Various matcher patterns

696

import static org.quartz.impl.matchers.GroupMatcher.*;

697

import static org.quartz.impl.matchers.KeyMatcher.*;

698

import static org.quartz.impl.matchers.NameMatcher.*;

699

700

// Group-based matching

701

listenerManager.addJobListener(listener, jobGroupEquals("reports"));

702

listenerManager.addJobListener(listener, jobGroupStartsWith("batch"));

703

listenerManager.addJobListener(listener, jobGroupContains("urgent"));

704

705

// Name-based matching

706

listenerManager.addJobListener(listener, jobNameEquals("importantJob"));

707

listenerManager.addJobListener(listener, jobNameEndsWith("Report"));

708

709

// Key-based matching

710

listenerManager.addJobListener(listener,

711

keyEquals(jobKey("specificJob", "specificGroup")));

712

713

// Complex matching with boolean operators

714

listenerManager.addJobListener(listener,

715

and(jobGroupEquals("reports"), jobNameEndsWith("Daily")));

716

717

listenerManager.addJobListener(listener,

718

or(jobGroupEquals("urgent"), jobGroupEquals("critical")));

719

720

listenerManager.addJobListener(listener,

721

not(jobGroupEquals("lowPriority")));

722

723

// Match everything

724

listenerManager.addJobListener(listener, anyJobGroup());

725

listenerManager.addTriggerListener(triggerListener, anyTriggerGroup());

726

```