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
相关产品推荐
相关产品推荐

