You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Batch 5任务重复执行问题:已运行任务仍重复启动

问题排查与修复方案

以下是导致你的Spring Batch任务重复启动的核心问题及对应修复:


1. 定时任务Cron表达式语法错误

你的Cron表达式"*/30* * * * *"存在语法问题,缺少30和*之间的空格,导致Spring无法正确解析为"每30秒执行一次"。

修复:

@Scheduled(cron = "*/30 * * * * *") // 补充空格,正确表示每30秒触发

2. 任务运行状态检查逻辑错误

你当前使用jobRepository.getLastJobExecution("RTGS-STEP1", new JobParametersBuilder().toJobParameters())来获取任务执行记录,但每次启动任务时都传入了唯一的startAtRTGSStep1时间戳参数,这会导致每次运行都生成新的JobInstance。而你用空参数去查询,根本找不到正在运行的任务实例,因此每次都会判定为"无运行任务"并启动新实例。

正确做法:
直接查询该Job下所有正在运行的执行记录,无需指定参数:

// 替换原有的状态检查逻辑
List<JobExecution> runningExecutions = jobRepository.findRunningJobExecutions("RTGS-STEP1");
if (runningExecutions.isEmpty()) {
    // 无运行任务,启动新实例
    log.info("RTGS batch step1 execution Started ");
    try {
        JobParameters jobParameters2 = new JobParametersBuilder()
                .addLong("startAtRTGSStep1", System.currentTimeMillis())
                .toJobParameters();
        jobLauncher.run(rtgsStep1Job, jobParameters2);
    } catch (Exception ex) {
        log.error("RTGS batch Step1 error: {}", ex.getMessage());
        ex.printStackTrace();
    }
} else {
    log.info("RTGS batch step1 execution isRunning ");
}

3. Job实例创建方式不规范

你每次启动任务时都调用eftJob.createEft()创建新的Job实例,这不符合Spring Batch的最佳实践(Job应为单例Bean),虽然不是直接导致重复启动的原因,但可能引发其他潜在问题。

修复:
将Job定义为单例Bean:

@Component
@RequiredArgsConstructor
@Slf4j
public class RtgsJob {
  private final ProcessorStep1 batchProcessorStep1;
  private final WriterStep1 batchWriterStep1;
  private final PlatformTransactionManager transactionManager;
  private final JobRepository jobRepository;

  @Bean // 定义为单例Bean
  public Job rtgsStep1Job(){
        return new JobBuilder("RTGS-STEP1", jobRepository)
                .incrementer(new RunIdIncrementer())
                .start(step1())
                .build();
    }

    private Step step1(){
        return new StepBuilder("step1", jobRepository)
                .<input, output> chunk(10, transactionManager)
                .reader(new ReaderStep1())
                .processor(batchProcessorStep1)
                .writer(batchWriterStep1)
                .build();
    }
}

然后在定时任务中直接注入该Job:

@Component
@Slf4j
public class ScheduledJobBean {
    @Autowired
    JobLauncher jobLauncher;
    @Autowired
    Job rtgsStep1Job; // 直接注入单例Job
    @Autowired
    private JobRepository jobRepository;

     @Scheduled(cron = "*/30 * * * * *")
    public void perform() throws Exception
    {
        List<JobExecution> runningExecutions = jobRepository.findRunningJobExecutions("RTGS-STEP1");
        if (runningExecutions.isEmpty()) {
            log.info("RTGS batch step1 execution Started ");
            try {
                JobParameters jobParameters2 = new JobParametersBuilder()
                        .addLong("startAtRTGSStep1", System.currentTimeMillis())
                        .toJobParameters();
                jobLauncher.run(rtgsStep1Job, jobParameters2);
            } catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException |
                     JobParametersInvalidException ex) {
                log.error("RTGS batch Step1 exception: {}", ex.getMessage());
                ex.printStackTrace();
            }catch (Exception ex) {
                log.error("RTGS batch Step1 error: {}", ex.getMessage());
                ex.printStackTrace();
            }
        }else{
            log.info("RTGS batch step1 execution isRunning ");
        }
    }
}

额外优化点

  • 你的日志语句中使用了{}占位符但未传入参数,建议补充参数或直接删除占位符,避免日志显示异常。
  • 可以考虑使用JobLauncher的同步执行模式(默认是异步),但如果你的任务本身是耗时操作,保持异步更合理。

内容的提问来源于stack exchange,提问作者Enamul Haque

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 13:31:08