因此,我已经创建了一个批量运行示例,以了解如何在满足条件之前重复工作。在大多数情况下,它按预期工作,但我在执行程序时获得以下日志条目
org.springframework.batch.core.job.SimpleStepHandler:在执行job = [infinateLoopJob]时检测到重复步骤[getStartingStep]。如果任一步骤失败,则两次都将在重新启动时再次执行。
虽然我被其他开发者告知,但这并不是什么大不了的事情,我宁愿做对,也不会有任何奇怪的事情发生在路上,当我想依靠这些知识时生产代码。我试图将时间戳生成附加到步骤的名称,但没有运气(它只在初始创建步骤时附加一次)。
简而言之,我怎么能拥有它,以便每个步骤都不会反复使用相同的名称,并且仍然执行循环整个作业的操作?
目前使用的代码:
AppStart.java
@SpringBootApplication(scanBasePackages="com.local.testJobLoop")
public class AppStart {
private static final Logger logger = LoggerFactory.getLogger(com.local.testJobLoop.AppStart.class);
AppStart() {
super();
}
public static void main(String[] args) {
SpringApplication application = new SpringApplication(AppStart.class);
application.setWebEnvironment(false);
ApplicationContext context = application.run(args);
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job infinateLoopJob = context.getBean("infinateLoopJob", Job.class);
try {
JobParameters jobParameters = new JobParametersBuilder()
.addLong("timestamp", System.currentTimeMillis())
.toJobParameters();
JobExecution execution = jobLauncher.run(infinateLoopJob, jobParameters);
BatchStatus status = execution.getStatus();
logger.debug("Exit Status : {}", status);
if (!BatchStatus.COMPLETED.equals(status)) {
List<Throwable> exceptions = execution.getAllFailureExceptions();
for (Throwable throwable : exceptions) {
logger.error("Batch Failure Exceptions:", throwable);
}
}
} catch (JobExecutionAlreadyRunningException e) {
logger.error("Job execution already running:", e);
} catch (JobRestartException e) {
logger.error("Illegal attempt to restart a job:", e);
} catch (JobInstanceAlreadyCompleteException e) {
logger.error("Illegal attempt to restart a job that was already completed successfully", e);
} catch (JobParametersInvalidException e) {
logger.error("Invalid job parameter:", e);
}
logger.debug("Done");
}
}
AppJobConfig.java
@Configuration
@EnableBatchProcessing
public class AppJobConfig {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Bean
public Job infinateLoopJob(@Qualifier("getStartingStep") final Step startingStep,
@Qualifier("getSecondStep") final Step secondStep) {
return jobBuilderFactory.get("infinateLoopJob")
.start(startingStep).on(Constants.STEP_EXIT_STATUS_CONTINUE).to(secondStep)
.from(startingStep).on(Constants.STEP_EXIT_STATUS_COMPLETED).end()
.from(secondStep).next(startingStep).build()
.build();
}
}
AppStepConfig.java
@Configuration
@EnableBatchProcessing
public class AppStepConfig {
@Autowired
private StepBuilderFactory stepBuilderFactory;
private static final Logger logger = LoggerFactory.getLogger(AppStepConfig.class);
@Bean
public Step getStartingStep(@Qualifier("startingActionTasklet") final StartingActionTasklet tasklet,
@Qualifier("startingActionListener") final StartingActionListener listener) {
return stepBuilderFactory.get("getStartingStep")
.tasklet(tasklet)
.listener(listener)
.build();
}
@Bean
public Step getSecondStep(@Qualifier("secondActionTasklet") final SecondActionTasklet tasklet,
@Qualifier("secondActionListener") final SecondActionListener listener) {
return stepBuilderFactory.get("getSecondStep")
.tasklet(tasklet)
.listener(listener)
.build();
}
StartingActionTasklet.java
@Component
public class StartingActionTasklet implements Tasklet, InitializingBean {
private static final Logger LOGGER = LoggerFactory.getLogger(StartingActionTasklet.class);
public StartingActionTasklet() { super(); }
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
int number = (int) chunkContext.getStepContext()
.getStepExecution()
.getJobExecution()
.getExecutionContext()
.get("incrementNumber");
LOGGER.info("STARTING ACTION: Number is {number}");
return RepeatStatus.FINISHED;
}
public void afterPropertiesSet() throws Exception { /* do nothing */ }
}
SecondActionTasklet.java
@Component
public class SecondActionTasklet implements Tasklet, InitializingBean {
private static final Logger LOGGER = LoggerFactory.getLogger(SecondActionTasklet.class);
public SecondActionTasklet() { super(); }
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
int number = (int) chunkContext.getStepContext()
.getStepExecution()
.getJobExecution()
.getExecutionContext()
.get("incrementNumber");
LOGGER.info("SECOND ACTION: Number is " + number);
number++;
LOGGER.info("SECOND ACTION: Number is now " + number);
chunkContext.getStepContext()
.getStepExecution()
.getJobExecution()
.getExecutionContext()
.put("incrementNumber", number);
return RepeatStatus.FINISHED;
}
public void afterPropertiesSet() throws Exception {
//do nothing
}
}
StartingActionListener.java
@Component
public class StartingActionListener implements StepExecutionListener {
private static final Logger LOGGER = LoggerFactory.getLogger(StartingActionListener.class);
public StartingActionListener() {
super();
}
public void beforeStep(StepExecution stepExecution) {
LOGGER.debug("StartingActionListener - beforeStep");
// Get incrementNumber from job execution context
JobExecution jobExecution = stepExecution.getJobExecution();
ExecutionContext jobContext = jobExecution.getExecutionContext();
Integer incrementNumber = (Integer) jobContext.get("incrementNumber");
if (incrementNumber == null) {
jobContext.put("incrementNumber", 0);
}
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
LOGGER.debug("StartingActionListener - afterStep");
// Get incrementNumber from job execution context
JobExecution jobExecution = stepExecution.getJobExecution();
ExecutionContext jobContext = jobExecution.getExecutionContext();
Integer incrementNumber = (Integer) jobContext.get("incrementNumber");
// Continue job execution if have more feed, stop otherwise
if (incrementNumber == null || incrementNumber > 10) {
return new ExitStatus(Constants.STEP_EXIT_STATUS_COMPLETED);
} else {
return new ExitStatus(Constants.STEP_EXIT_STATUS_CONTINUE);
}
}
}
SecondActionListener.java
@Component
public class SecondActionListener implements StepExecutionListener {
private static final Logger LOGGER = LoggerFactory.getLogger(SecondActionListener.class);
public void beforeStep(StepExecution stepExecution) {
}
public ExitStatus afterStep(StepExecution stepExecution) {
LOGGER.debug("SecondActionListener - afterStep");
return null;
}
}
答案 0 :(得分:1)
业务规则是否要求starting step
和second step
需要分开且不同?如果没有,最简单的方法是将它们合并为一个步骤并利用Repeat功能。
实际上,合并的Tasklet
只会返回RepeatStatus.CONTINUABLE
,直到所有工作完成,此时它将返回RepeatStatus.FINISHED
。
更新:所以你可以做的就是为你的工作增加一个“decisionStepThree”,为工作添加新的步骤。
public class DecisionStepThreeTasklet implements Tasklet {
@Autowired
private SimpleJob job;
@Autowired
private Step startingStep;
@Autowired
private Step secondStep;
public RepeatStatus execute(final StepContribution contribution, final ChunkContext chunkContext) {
Collection<StepExecution> stepExecutions = chunkContext.getStepContext().
getStepExecution().getJobExecution().getStepExecutions();
int stepCount = stepExecutions.size();
StepExecution lastStepExecution = getLastStep(stepExecutions);
if (Constants.STEP_EXIT_STATUS_CONTINUE.equals(lastStepExecution.getExitStatus().getExitCode())) {
job.addStep(copyStep(startingStep, "startingStep" + ++stepCount));
job.addStep(copyStep(secondStep, "secondStep" + ++stepCount));
}
return RepeatStatus.FINISHED;
}
public StepExecution getLastStep(final Collection<StepExecution> c) {
Iterator<StepExecution> itr = c.iterator();
StepExecution lastElement = itr.next();
while(itr.hasNext()) {
lastElement=itr.next();
}
return lastElement;
}
private Step copyStep(final Step parent, final String name) {
return new Step() {
public String getName() {
return name;
}
public boolean isAllowStartIfComplete() {
return parent.isAllowStartIfComplete();
}
public int getStartLimit() {
return parent.getStartLimit();
}
public void execute(final StepExecution stepExecution) throws JobInterruptedException {
parent.execute(stepExecution);
}
};
}
}