jeecgboot/JeecgBoot · error · JeecgBootException
删除定时任务失败
Error message
删除定时任务失败
What it means
The catch-all in QuartzJobServiceImpl.schedulerDelete fires when any exception occurs during pauseTrigger, unscheduleJob, or deleteJob. The underlying cause is only written to the server log (log.error) and is intentionally NOT included in the user-facing message, so root-cause debugging requires reading the log rather than the API response.
Source
Thrown at jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/service/impl/QuartzJobServiceImpl.java:173
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) {
log.error(e.getMessage(), e);
throw new JeecgBootException("删除定时任务失败");
}
}
/**
* 安全加载Job类:仅允许 org.jeecg. 包下的类,且必须实现 org.quartz.Job 接口
*/
private static Job getClass(String classname) throws Exception {
// 包名白名单校验,防止任意类实例化导致RCE
if (classname == null || !classname.startsWith("org.jeecg.")) {
throw new IllegalArgumentException("非法的任务类名:" + classname + ",仅允许 org.jeecg 包下的Job类");
}
//update-begin---author:scott ---date:20260416 for:【PR#9538】Class.forName使用上下文类加载器,增强部署兼容性-----------
Class<?> clazz = Class.forName(classname, true, Thread.currentThread().getContextClassLoader());
//update-end---author:scott ---date:20260416 for:【PR#9538】Class.forName使用上下文类加载器,增强部署兼容性-----------
// 校验是否实现了 org.quartz.Job 接口
if (!Job.class.isAssignableFrom(clazz)) {
throw new IllegalArgumentException("非法的任务类:" + classname + ",必须实现 org.quartz.Job 接口");
}View on GitHub (pinned to 96fb33f5ec)
Solutions
- Read the server log line written by log.error(e.getMessage(), e) to obtain the real cause.
- Verify the QRTZ_* tables exist and are reachable from the configured datasource.
- If the trigger is already gone, remove the dangling sys_quartz_job row manually.
- Ensure the scheduler bean is started (not in standby) before issuing delete.
Example fix
// before
private void schedulerDelete(String id) {
try { scheduler.pauseTrigger(TriggerKey.triggerKey(id)); ... }
catch (Exception e) { log.error(e.getMessage(), e); throw new JeecgBootException("删除定时任务失败"); }
}
// after: surface the cause for diagnostics and guard null id
private void schedulerDelete(String id) {
if (id == null || id.isBlank()) throw new JeecgBootException("trigger id 不能为空");
try { scheduler.pauseTrigger(TriggerKey.triggerKey(id)); ... }
catch (Exception e) { throw new JeecgBootException("删除定时任务失败: " + e.getMessage(), e); }
} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check the trigger exists before attempting delete, to avoid the catch-all.
private boolean triggerExists(String id) {
try {
return scheduler.getTrigger(TriggerKey.triggerKey(id)) != null;
} catch (SchedulerException e) {
return false;
}
}
if (id == null || id.isBlank() || !triggerExists(id)) {
// nothing to delete; treat as success or return a clear message
} Try / catch
try {
quartzJobService.delete(id);
} catch (JeecgBootException e) {
// The real cause is in the server log (log.error in schedulerDelete).
log.warn("删除定时任务失败 id={}, 请查看后端日志获取根因", id);
return Result.error("删除失败, 请联系管理员查看日志");
} Prevention
- Always correlate the server log timestamp with the failed delete to recover the swallowed cause.
- Ensure QRTZ_* tables are part of every environment's DB setup/migration.
- Avoid deleting jobs directly in the DB; use the API so sys_quartz_job and the scheduler stay in sync.
- Guard null/empty ids before calling schedulerDelete.
When it happens
Trigger: Deleting a job whose TriggerKey/JobKey was already removed from the Quartz store; the QRTZ_* JDBC tables are unreachable, locked, or missing; clustered scheduler contention/timeout; passing a null or empty id (TriggerKey.triggerKey(null)).
Common situations: Job was already deleted directly in the DB leaving a dangling sys_quartz_job row; Quartz tables not migrated/created in a new environment; cluster misconfiguration; the scheduler is in standby/error state.
Related errors
- 创建定时任务失败
- 后台找不到该类名:${jobClassName}
- ${e.getMessage()}
- 非法的任务类名:${classname},仅允许 org.jeecg 包下的Job类
- 非法的任务类:${classname},必须实现 org.quartz.Job 接口
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/5fb989154e67db6e.
Report an issue: GitHub.