首次Spring Batch Job执行成功后后续任务变NOOP的原因及解决
问题描述
配置了Spring Batch任务并通过@Scheduled定时触发,首次Job执行状态为COMPLETED,但后续触发的任务均变为NOOP状态不再实际运行。
相关代码如下:
Batch配置类:
import kr.piehealthcare.point.core.domain.user.UserRepository import mu.KotlinLogging import org.springframework.batch.core.Job import org.springframework.batch.core.Step import org.springframework.batch.core.configuration.annotation.StepScope import org.springframework.batch.core.job.builder.JobBuilder import org.springframework.batch.core.repository.JobRepository import org.springframework.batch.core.step.builder.StepBuilder import org.springframework.batch.core.step.tasklet.Tasklet import org.springframework.batch.repeat.RepeatStatus import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.transaction.PlatformTransactionManager private val log = KotlinLogging.logger { } @Configuration class BatchConfig( val jobRepository: JobRepository, val transactionManager: PlatformTransactionManager, val userRepository: UserRepository ){ @Bean fun myJob(): Job { return JobBuilder("taskletJob", jobRepository) .start(myStep()) .build() } @Bean fun myStep(): Step { return StepBuilder("taskletStep", jobRepository) .tasklet(myTask(), transactionManager) .build() } @Bean @StepScope fun myTask(): Tasklet { return Tasklet { _, _ -> log.info { "test" } RepeatStatus.FINISHED } } }
定时触发代码:
@Scheduled(cron = "* * * * * *") fun batchGo(){ val jobParameters = JobParameters() val jobExecution: JobExecution = jobLauncher.run(batchConfig.myJob(), jobParameters) if (jobExecution.status == BatchStatus.COMPLETED) { println("batch success") } else { println("error") } }
原因分析
Spring Batch通过Job名称+JobParameters的组合唯一标识一次Job执行。当重复提交同一个Job且使用完全相同的JobParameters时,Spring Batch会判定这是重复执行请求(该Job+参数的组合已执行完成),直接返回NOOP(无操作)状态,不会实际运行任务逻辑。
你当前代码中每次触发定时任务都传入空的JobParameters(),导致每次参数组合完全一致,首次执行完成后,后续所有触发都会被判定为重复请求。
解决方案
要实现同一Job的多次重复执行,只需每次触发时传入唯一的JobParameters,让Spring Batch识别为新的执行请求。最常用的方式是添加当前时间戳作为参数,确保每次参数不同。
修改后的定时触发代码如下:
import org.springframework.batch.core.JobParametersBuilder import java.util.Date @Scheduled(cron = "* * * * * *") fun batchGo(){ // 添加当前时间作为唯一参数 val jobParameters = JobParametersBuilder() .addDate("timestamp", Date()) .toJobParameters() val jobExecution: JobExecution = jobLauncher.run(batchConfig.myJob(), jobParameters) if (jobExecution.status == BatchStatus.COMPLETED) { println("batch success") } else { println("error") } }
另外,若无需保留执行历史,也可在Job配置时禁用重复检查,但这种方式不推荐(丢失执行轨迹,不利于问题排查):
@Bean fun myJob(): Job { return JobBuilder("taskletJob", jobRepository) .start(myStep()) .preventRestart(false) // 禁用重复检查(不推荐) .build() }
内容的提问来源于stack exchange,提问作者madol
相关产品推荐
相关产品推荐

