jeecgboot/JeecgBoot · error · JeecgBootException

创建定时任务失败

Error message

创建定时任务失败

What it means

Thrown by QuartzJobServiceImpl.schedulerAdd when the Quartz SchedulerException is raised while scheduling a new job (scheduler.scheduleJob). This typically means the job could not be registered with the Quartz scheduler - most often a duplicate JobKey/TriggerKey, scheduler in a bad state, or the scheduler failed to start. The original SchedulerException is chained as the cause.

Source

Thrown at jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/service/impl/QuartzJobServiceImpl.java:153

	 * @param parameter
	 */
	private void schedulerAdd(String id, String jobClassName, String cronExpression, String parameter) {
		try {
			// 启动调度器
			scheduler.start();

			// 构建job信息
			JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(id).usingJobData("parameter", parameter).build();

			// 表达式调度构建器(即任务执行的时间)
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

			// 按新的cronExpression表达式构建一个新的trigger
			CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(id).withSchedule(scheduleBuilder).build();

			scheduler.scheduleJob(jobDetail, trigger);
		} catch (SchedulerException e) {
			throw new JeecgBootException("创建定时任务失败", e);
		} catch (RuntimeException e) {
			throw new JeecgBootException(e.getMessage(), e);
		}catch (Exception e) {
			throw new JeecgBootException("后台找不到该类名:" + jobClassName, e);
		}
	}

	/**
	 * 删除定时任务
	 * 
	 * @param id
	 */
	private void schedulerDelete(String id) {
		try {
			scheduler.pauseTrigger(TriggerKey.triggerKey(id));
			scheduler.unscheduleJob(TriggerKey.triggerKey(id));
			scheduler.deleteJob(JobKey.jobKey(id));
		} catch (Exception e) {

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Check the chained SchedulerException (the 'cause') for the exact Quartz error code - commonly 'ObjectAlreadyExistsException' for a duplicate key.
  2. Ensure schedulerDelete runs before schedulerAdd when reusing the same id; verify the QRTZ_JOB_DETAILS / QRTZ_TRIGGERS tables do not contain a stale row for the id.
  3. In clustered mode, confirm all nodes share the same JDBC store and clock; clean orphaned rows if a node crashed mid-update.

Example fix

// before: schedulerAdd(id="42",...) called while QRTZ_TRIGGERS still has TRIGGER_NAME="42"
// after:  // delete the stale trigger first
//         scheduler.pauseTrigger(TriggerKey.triggerKey("42"));
//         scheduler.unscheduleJob(TriggerKey.triggerKey("42"));
//         scheduler.deleteJob(JobKey.jobKey("42"));
//         schedulerAdd("42", ...);
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure no stale key before adding
try {
    scheduler.deleteJob(JobKey.jobKey(id));
} catch (SchedulerException ignore) {}
// then schedulerAdd(...)

Try / catch

try {
    quartzJobService.saveAndSchedule(job);
} catch (JeecgBootException e) {
    if (e.getMessage().contains("创建定时任务失败") && e.getCause() instanceof SchedulerException) {
        // inspect cause; if ObjectAlreadyExistsException, delete stale key then retry once
    }
}

Prevention

When it happens

Trigger: Adding a Quartz job whose id already exists in the scheduler; scheduler.start() failed; the trigger with the same key already registered; running in clustered Quartz mode where another node holds the key.

Common situations: Re-adding a job that was paused but not deleted (the JobKey still lives in the scheduler); restart race in a clustered Quartz deployment; the QRTZ tables are dirty/inconsistent after a failed migration.

Related errors


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/ca96060b079a83a8. Report an issue: GitHub.