Spring Batch stop job execution from external class

徘徊边缘 提交于 2021-01-28 09:54:16

问题


I have an existing spring batch project that have multiple steps. I want to modify a step so I can stop the job : jobExecution.getStatus() == STOPPED.

My step :

@Autowired
public StepBuilderFactory stepBuilderFactory;
@Autowired
private StepReader reader;
@Autowired
private StepProcessor processor;
@Autowired
private StepWriter writer;
@Autowired
public GenericListener listener;
@Bean
@JobScope
@Qualifier("mystep")
public Step MyStep() throws ReaderException {
    return stepBuilderFactory.get("mystep")
            .reader(reader.read())
            .listener(listener)
            .processor(processor)
            .writer(writer)
            .build();
}

GenericListener implements ItemReadListener, ItemProcessListener, ItemWriteListener and overrides before and after methods that basically write log.

The focus here is on the StepReader class and its read() method that returns a FlatFileItemReader :

@Component
public class StepReader {
    public static final String DELIMITER = "|";
    @Autowired
    private ClassToAccessProperties classToAccessProperties;
    private Logger log = Logger.create(StepReader.class);
    @Autowired
    private FlatFileItemReaderFactory<MyObject> flatFileItemReaderFactory;

    public ItemReader<MyObject> read() throws ReaderException {
        try {
            String csv = classToAccessProperties.getInputCsv();
            FlatFileItemReader<MyObject> reader = flatFileItemReaderFactory.create(csv, getLineMapper());
            return reader;
        } catch (ReaderException | EmptyInputfileException | IOException e) {
            throw new ReaderException(e);
        } catch (NoInputFileException e) {
            log.info("Oh no !! No input file");
            // Here I want to stop the job
            return null;
        }
    }
    private LineMapper<MyObject> getLineMapper () {
        DefaultLineMapper<MyObject> mapper = new DefaultLineMapper<>();
        DelimitedLineTokenizer delimitedLineTokenizer = new DelimitedLineTokenizer();
        delimitedLineTokenizer.setDelimiter(DELIMITER);
        mapper.setLineTokenizer(delimitedLineTokenizer);
        mapper.setFieldSetMapper(new MyObjectFieldSetMapper());
        return mapper;
    }
}

I tried to implement StepExecutionListener in StepReader but with no luck, I think because the reader method in StepBuilderFactory is expecting an ItemReader from the reader.read() method and it doesn't care about the rest of the class.

I'm looking for ideas or solution to be able to stop the entire job (not fail it) when NoInputFileException is catched.


回答1:


I'm looking for ideas or solution to be able to stop the entire job (not fail it) when NoInputFileException is catched.

This is a common pattern and is described in details in the Handling Step Completion When No Input is Found section of the reference documentation. The example in that section shows how to fail a job when no input file is found, but since you want to stop the job instead of failing it, you can use StepExecution#setTerminateOnly(); in the listener and your job will end with status STOPPED. In your example, you would add that listener to the MyStep step.

However, I would suggest to add a pre-validation step and stop the job if there is no file. Here is a quick example:

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableBatchProcessing
public class MyJob {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Bean
    public Step fileValidationStep() {
        return steps.get("fileValidationStep")
                .tasklet((contribution, chunkContext) -> {
                    // TODO add code to check if the file exists
                    System.out.println("file not found");
                    chunkContext.getStepContext().getStepExecution().setTerminateOnly();
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Step fileProcessingStep() {
        return steps.get("fileProcessingStep")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("processing file");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Job job() {
        return jobs.get("job")
                .start(fileValidationStep())
                .next(fileProcessingStep())
                .build();
    }

    public static void main(String[] args) throws Exception {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyJob.class);
        JobLauncher jobLauncher = context.getBean(JobLauncher.class);
        Job job = context.getBean(Job.class);
        JobExecution jobExecution = jobLauncher.run(job, new JobParameters());
        System.out.println("Job status: " + jobExecution.getExitStatus().getExitCode());
    }

}

The example prints:

file not found
Job status: STOPPED

Hope this helps.



来源:https://stackoverflow.com/questions/55499965/spring-batch-stop-job-execution-from-external-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!