elunez/eladmin · error · BadRequestException

子任务中不能添加当前任务ID

Error message

子任务中不能添加当前任务ID

What it means

On job update, if the subTask field (comma-separated list of job IDs to chain after this job) is non-blank, QuartzJobServiceImpl.update splits it on both ',' and the full-width ',' and rejects the request if the resulting list contains the job's own id. Allowing it would make the job re-trigger itself, causing infinite recursive execution.

Source

Thrown at eladmin-system/src/main/java/me/zhengjie/modules/quartz/service/impl/QuartzJobServiceImpl.java:97

    @Transactional(rollbackFor = Exception.class)
    public void create(QuartzJob resources) {
        if (!CronExpression.isValidExpression(resources.getCronExpression())){
            throw new BadRequestException("cron表达式格式错误");
        }
        resources = quartzJobRepository.save(resources);
        quartzManage.addJob(resources);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(QuartzJob resources) {
        if (!CronExpression.isValidExpression(resources.getCronExpression())){
            throw new BadRequestException("cron表达式格式错误");
        }
        if(StringUtils.isNotBlank(resources.getSubTask())){
            List<String> tasks = Arrays.asList(resources.getSubTask().split("[,,]"));
            if (tasks.contains(resources.getId().toString())) {
                throw new BadRequestException("子任务中不能添加当前任务ID");
            }
        }
        resources = quartzJobRepository.save(resources);
        quartzManage.updateJobCron(resources);
    }

    @Override
    public void updateIsPause(QuartzJob quartzJob) {
        // 置换暂停状态
        if (quartzJob.getIsPause()) {
            quartzManage.resumeJob(quartzJob);
            quartzJob.setIsPause(false);
        } else {
            quartzManage.pauseJob(quartzJob);
            quartzJob.setIsPause(true);
        }
        quartzJobRepository.save(quartzJob);
    }

View on GitHub (pinned to 55fbf70595)

Solutions

  1. Remove the job's own ID from its subTask field; subTask should only contain OTHER job IDs to run after completion.
  2. If chaining behavior on itself is genuinely needed, restructure into two jobs that reference each other's IDs (and re-check whether recursion is intended at all).
  3. Filter the current ID out in the frontend picker before submitting.

Example fix

// before
{"id": "5", "subTask": "5,8,9"} // self-reference -> rejected
// after
{"id": "5", "subTask": "8,9"}
Defensive patterns

Strategy: validation

Validate before calling

// strip self-reference before saving
List<String> ids = Arrays.stream(subTask.split("[,,]"))
    .map(String::trim).filter(s -> !s.equals(String.valueOf(jobId))).collect(Collectors.toList());
String safe = String.join(",", ids);

Type guard

boolean subTaskIsSafe(String subTask, Long selfId) {
    if (StringUtils.isBlank(subTask)) return true;
    return Arrays.stream(subTask.split("[,,]"))
        .map(String::trim)
        .noneMatch(s -> s.equals(String.valueOf(selfId)));
}

Prevention

When it happens

Trigger: PUT /api/quartz/jobs with subTask containing the job's own ID, e.g. updating job id=5 with subTask='5,6' or '5,6'. String comparison is used, so both '5' and any exact string match on the ID triggers it.

Common situations: Copy-pasting a job's full subTask chain into itself when cloning configurations; UI dropdown listing all jobs including the current one; misunderstanding subTask as a dependency list and adding the parent.

Related errors


AI-assisted analysis of elunez/eladmin@55fbf70595 (2026-08-14). Data as JSON: /api/errors/8ddf8b9ac9de034a. Report an issue: GitHub.