MRX
MRX

Reputation: 1651

Spring Batch Job Running in Infinite loop

I am working on simple Spring Batch Job. When I launch job its running in infinite loop. It doesn't stop. According to my scheduler time it should run after every 10 seconds. But when job starts it doesn't stop. Its just keeps printing sysouts from reader, processor and writer respectively. I am creating job with reader, processor and writer. And I am doing all configuration by annotations. Not by xml.

Here is Batch Configuration

@Configuration
@EnableBatchProcessing
@EnableScheduling
public class BatchJobConfig {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Autowired
    private SimpleJobLauncher jobLauncher;

    @Scheduled(cron="*/10 * * * * *")
    public void perform() throws Exception 
    {
        Job job = job(step1());
        JobParameters jobParameters = new JobParameters();
        jobLauncher.run(job, jobParameters);        
    }

    @Bean
    public Step step1() 
    {
        return stepBuilderFactory.get("step1").<Person, Person> chunk(1)
                .reader(reader()).processor(processor()).writer(writer())
                .build();
    }

    @Bean
    public Job job(Step step1) throws Exception 
    {
        return jobBuilderFactory.get("job")
                .incrementer(new RunIdIncrementer()).flow(step1())
                .end().build();
    }

    @Bean
    public DataSource dataSource()
    {
        EmbeddedDatabaseBuilder embeddedDatabaseBuilder = new EmbeddedDatabaseBuilder();
        return embeddedDatabaseBuilder.addScript("classpath:org/springframework/batch/core/schema-drop-hsqldb.sql")
                .addScript("classpath:org/springframework/batch/core/schema-hsqldb.sql")
                .setType(EmbeddedDatabaseType.HSQL)
                .build();
    }

    @Bean
    public PersonReader reader() {
        return new PersonReader();
    }
    @Bean
    public PersonWriter writer() {
        return new PersonWriter();
    }
    @Bean
    public PersonProcessor processor() {
        return new PersonProcessor();
    }

    @Bean
    public MapJobRepositoryFactoryBean mapJobRepositoryFactory(ResourcelessTransactionManager txManager) throws Exception  {    
        MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean(txManager);
        factory.afterPropertiesSet();
        return factory;
    }
    @Bean
    public JobRepository jobRepository(MapJobRepositoryFactoryBean factory) throws Exception {
        return factory.getObject();
    }
    @Bean
    public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
        SimpleJobLauncher launcher = new SimpleJobLauncher();
        launcher.setJobRepository(jobRepository);
        return launcher;
    }
    @Bean
    public ResourcelessTransactionManager transactionManager() {
        return new ResourcelessTransactionManager();
    }
}

PersonReader.java

  public class PersonReader implements ItemReader<Person> {
    @Override
    public Person read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
        Person person = new Person();
        System.out.println("In PersonReader");
        return person;
    }
}

PersonWriter.java

public class PersonWriter implements ItemWriter<Person> {
    @Override
    public void write(List<? extends Person> arg0) throws Exception {
        System.out.println("IN PersonWriter");
    }
}

PersonProcessor.java

public class PersonProcessor implements ItemProcessor<Person, Person> {
    @Override
    public Person process(Person arg0) throws Exception  {
        System.out.println("In PersonProcessor");
        return arg0;
    }
}

Upvotes: 5

Views: 17896

Answers (4)

Sadanand Burud
Sadanand Burud

Reputation: 11

Use the interface StepExecutionListener. This will provide two methods

Use a variable boolean FLAG at instance level.

public class PersonReader implements ItemReader<Person>,StepExecutionListener {
    private boolean jobState = false;

    @Override
    public Person read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
        if(!jobState){
            Person person = new Person();
            System.out.println("In PersonReader");
            jobState=true;
            return person;
        }
        return null;
    }
}



@Override
public void beforeStep(StepExecution stepExecution) { }

  @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
    
        jobStat = false;
        return stepExecution.getExitStatus();
    }
}
  1. before read() method execution beforeStep method executes.
  2. read() method set a flag to true.
  3. after read() method execution, afterStep method will executes and set the flag as false.
  4. Whenever your scheduler start the job after 10 minutes the value will be false initially.

Upvotes: 1

Dherik
Dherik

Reputation: 19130

Is someone came here with the same error, but using FlatFileItemReader (what is a Reader implementation), see if you have more than one step with the same name.

I had two steps on my Spring Batch project with the same name. The last step among this two executed caused a infinite loop.

Upvotes: 1

Anuj Vishwakarma
Anuj Vishwakarma

Reputation: 842

Add a flag to resist the reader to run in infinite loop.

Reader:

public class PersonReader implements ItemReader<Person> {
    private boolean batchJobState = false;

    @Override
    public Person read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
        if(!batchJobState){
            Person person = new Person();
            System.out.println("In PersonReader");
            batchJobState=true;
            return person;
        }
        return null;
    }
}

Upvotes: 4

Michael Minella
Michael Minella

Reputation: 21503

A step will run until your ItemReader returns null. In your case, your ItemReader never does (it always returns a new Person) so it will never end.

Upvotes: 25

Related Questions