- 
                Notifications
    
You must be signed in to change notification settings  - Fork 2.5k
 
Implementation of JobLauncher that is tolerant on failures and accept… #440
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…s retry template to do the actual restart/retry.
| 
           Hi @bojanv55 , According to BATCH-266 and BATCH-1329, this feature is out of scope and should be left to the user to implement either with an AOP advise or by wrapping the  Here is a quick example: import java.util.Map;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
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.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;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
@Configuration
@EnableBatchProcessing
public class MyJob {
	private final JobBuilderFactory jobs;
	private final StepBuilderFactory steps;
	@Autowired
	public MyJob(JobBuilderFactory jobs, StepBuilderFactory steps) {
		this.jobs = jobs;
		this.steps = steps;
	}
	@Bean
	public Step step() {
		return steps.get("step")
				.tasklet((contribution, chunkContext) -> {
					Map<String, Object> jobParameters = chunkContext.getStepContext().getJobParameters();
					String name = (String) jobParameters.get("name");
					System.out.println("Hello " + name);
					throw new Exception("Boom!");
				})
				.build();
	}
	@Bean
	public Job job() {
		return jobs.get("job")
				.start(step())
				.build();
	}
	public static void main(String[] args) throws Throwable {
		RetryTemplate retryTemplate = new RetryTemplate();
		retryTemplate.setRetryPolicy(new SimpleRetryPolicy(3));
		ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyJob.class);
		JobLauncher jobLauncher = applicationContext.getBean(JobLauncher.class);
		Job job = applicationContext.getBean(Job.class);
		JobParameters jobParameters = new JobParametersBuilder().addString("name", "world").toJobParameters();
		retryTemplate.execute(retryContext -> {
			JobExecution jobExecution = jobLauncher.run(job, jobParameters);
			if (!jobExecution.getAllFailureExceptions().isEmpty()){
                                System.out.println("Job failed, retrying..");
				throw jobExecution.getAllFailureExceptions().iterator().next();
			}
			return jobExecution;
		});
	}
}This will print: and then fail. Do you agree? Kr,  | 
    
| 
           @bojanv55 Any update on this?  | 
    
| 
           Sure, this is another option. You can close this MR then.  | 
    
| 
           @benas Will the retrytemplate work with itemreader, itemprocessor and itemwriter too. Because I see retry doesn't happen when I changed your code to use itemreader and itemwriter. package com.nielsen.watch.tam.ncl.etl.config;
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.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
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;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import java.util.Arrays;
@Configuration
@EnableBatchProcessing
public class MyJob {
  private final JobBuilderFactory jobs;
  private final StepBuilderFactory steps;
  @Autowired
  public MyJob(JobBuilderFactory jobs, StepBuilderFactory steps) {
    this.jobs = jobs;
    this.steps = steps;
  }
  @Bean
  public Step step() {
    return steps.get("step")
      .<Integer, Integer>chunk(2)
      .reader(itemReader())
      .writer(itemWriter())
      //.faultTolerant()
      //.retryLimit(5)
      //.retry(Exception.class)
      .build();
  }
  @Bean
  public ItemReader<Integer> itemReader() {
    return new ListItemReader<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
  }
  @Bean
  public ItemWriter<Integer> itemWriter() {
    return items -> {
      for (Integer item : items) {
        System.out.println("item = " + item);
        if (item.equals(7)) {
          throw new Exception("Sevens are sometime nasty, let's retry them");
        }
      }
    };
  }
  @Bean
  public Job job() {
    return jobs.get("job")
      .start(step())
      .build();
  }
  public static void main(String[] args) throws Throwable {
    RetryTemplate retryTemplate = new RetryTemplate();
    retryTemplate.setRetryPolicy(new SimpleRetryPolicy(3));
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyJob.class);
    JobLauncher jobLauncher = applicationContext.getBean(JobLauncher.class);
    Job job = applicationContext.getBean(Job.class);
    //JobParameters jobParameters = new JobParametersBuilder().addString("name", "world").toJobParameters();
    retryTemplate.execute(retryContext -> {
      JobExecution jobExecution = jobLauncher.run(job, new JobParameters());
      if (!jobExecution.getAllFailureExceptions().isEmpty()) {
        System.out.println("Job failed, retrying..");
        throw jobExecution.getAllFailureExceptions().iterator().next();
      }
      return jobExecution;
    });  
   }
} | 
    
          
 No, the retry template I used in the example is external to the job definition. I could have used plain java code or any other library (like retry4j, failsafe or guava-retrying) to retry the job after a failure, but since we are a Spring shop, I used a  When you configure a retry policy on a chunk-oriented step through the   | 
    
…s retry template to do the actual restart/retry.