执行作业时检测到重复步骤

时间:2017-05-09 16:58:37

标签: java spring spring-batch

因此,我已经创建了一个批量运行示例,以了解如何在满足条件之前重复工作。在大多数情况下,它按预期工作,但我在执行程序时获得以下日志条目

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;
    }
}

1 个答案:

答案 0 :(得分:1)

业务规则是否要求starting stepsecond 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);
            }
        };
    }    
}