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
- Check the chained SchedulerException (the 'cause') for the exact Quartz error code - commonly 'ObjectAlreadyExistsException' for a duplicate key.
- 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.
- 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
- Always call schedulerDelete before schedulerAdd when reusing an id.
- Keep the QRTZ tables clean after failed migrations or crashes.
- In clustered Quartz, ensure all nodes share the JDBC store and an NTP-synced clock.
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
- ${e.getMessage()}
- 后台找不到该类名:${jobClassName}
- 删除定时任务失败
- Invalid expression has too many terms: {expression}
- Support for specifying 'L' with other days of the week is no
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/ca96060b079a83a8.
Report an issue: GitHub.