Spring batch: restart the task, and then automatically start the next task

I need to create a recovery template. In my template, I can only run a task in a specific time window. If the task fails, it will only be restarted in the next time window, and when I finished, I would like to start the schedule task that was scheduled in advance for this window. The only difference between jobs is the time window options.

I was thinking about JobExecutionDecider along with JobExplorer or Joblauncher overrides. But everything seems too intrusive.

I was not able to find an example that fits my needs. Ideas would be welcome.

+2
source share
3 answers

, , incomplete-co.de. , . , . , .

<batch:job id="recoveryWrapper"
       incrementer="wrapperRunIdIncrementer"
       restartable="true">
    <batch:decision id="recoveryFlowDecision" decider="recoveryFlowDecider">
        <batch:next on="FIRST_RUN" to="defineParametersOnFirstRun" />
        <batch:next on="RECOVER" to="recover.batchJob " />
        <batch:next on="CURRENT" to="current.batchJob " />
    </batch:decision>
    <batch:step id="defineParametersOnFirstRun" next="current.batchJob">
        <batch:tasklet ref="defineParametersOnFirstRunTasklet"/>
    </batch:step>
    <batch:step id="recover.batchJob " next="current.batchJob">
        <batch:job ref="batchJob" job-launcher="jobLauncher"
                            job-parameters-extractor="jobParametersExtractor" />
    </batch:step>
    <batch:step id="current.batchJob" >
       <batch:job ref="batchJob" job-launcher="jobLauncher"
                            job-parameters-extractor="jobParametersExtractor" />
    </batch:step>
</batch:job>

RecoveryFlowDecider JobParametersExtractor Spring . RecoveryFlowDecider JobExplorer JobRepository, , . , JobParametersExtractor. runIdIncremeter, .

@Component
 public class RecoveryFlowDecider implements JobExecutionDecider {
        private static final String FIRST_RUN = "FIRST_RUN";
        private static final String CURRENT = "CURRENT";
        private static final String RECOVER = "RECOVER";

        @Autowired
        private JobExplorer jobExplorer;
        @Autowired
        private JobRepository jobRepository;

        @Override
        public FlowExecutionStatus decide(JobExecution jobExecution
                                         ,StepExecution stepExecution) {
            // the wrapper is named as the wrapped job + WRAPPER
            String wrapperJobName = jobExecution.getJobInstance().getJobName();
            String jobName;
             jobName = wrapperJobName.substring(0,wrapperJobName.indexOf(EtlConstants.WRAPPER));
            List<JobInstance> instances = jobExplorer.getJobInstances(jobName, 0, 1);
                JobInstance internalJobInstance = instances.size() > 0 ? instances.get(0) : null;

            if (null == internalJobInstance) {
                return new FlowExecutionStatus(FIRST_RUN);
            }
            JobExecution lastExecution = jobRepository.getLastJobExecution(internalJobInstance.getJobName()
    ,internalJobInstance.getJobParameters());
            //place the last execution on the context (wrapper context to use later)
            jobExecution.getExecutionContext().put(EtlConstants.LAST_EXECUTION, lastExecution);
                ExitStatus exitStatus = lastExecution.getExitStatus();

            if (ExitStatus.FAILED.equals(exitStatus) || ExitStatus.UNKNOWN.equals(exitStatus)) {
                return new FlowExecutionStatus(RECOVER);
            }else if(ExitStatus.COMPLETED.equals(exitStatus)){
                return new FlowExecutionStatus(CURRENT);    
            }
            //We should never get here unless we have a defect
            throw new RuntimeException("Unexpecded batch status: "+exitStatus+" in decider!");

        }

}

JobParametersExtractor , , Spring Bacth. .

    @Component
    public class JobExecutionWindowParametersExtractor implements
            JobParametersExtractor {
        @Override
        public JobParameters getJobParameters(Job job, StepExecution stepExecution) {

            // Read the last execution from the wrapping job
            // in order to build Next Execution Window
            JobExecution lastExecution= (JobExecution) stepExecution.getJobExecution().getExecutionContext().get(EtlConstants.LAST_EXECUTION);;

            if(null!=lastExecution){
                if (ExitStatus.FAILED.equals(lastExecution.getExitStatus())) {
                    JobInstance instance = lastExecution.getJobInstance();
                    JobParameters parameters = instance.getJobParameters();                 
                                return parameters;
                }
            }       
            //We do not have failed execution or have no execution at all we need to create a new execution window
            return buildJobParamaters(lastExecution,stepExecution);
        }
...
}
+2

JobStep? , - . StepExecutionContext. JobExecutionDecider ; , JobStep, Job.

http://docs.spring.io/spring-batch/reference/htmlsingle/#external-flows

+2

Can this be done in the opposite way?

In each time window, submit the task intended for this time window.

However, the very first step of the task is to check whether the task was completed successfully in the previous time window or not. If this does not succeed, submit the previous task and wait for completion before moving on to its own logic.

0
source

All Articles