작성
·
510
0
안녕하세요 이번 강의에서 RetryItemProcessor2 클래스에서
new DefaultRetryState(item, rollbackClassifier)를 추가하게 되면서 retry가 1번만 발생하게 되더라고요.
Configuration에서 RetryPolicy로 maxAttempts를 2로 줬는데 왜 1번만 retry를 하는걸까요?
제가 디버깅하면서 보니까 처음 재시도때는 RetryPolicy가 Configuration에서 정의한 RetryPolicy가 적용됐는데, 2번째 재시도 하려고 할때 RetryPolicy가 SimpleRetryPolicy가 maxAttempts가 0인상태로, configuration에서 정의한 RetryPolicy가 아니더라고요.
왜 이렇게 된건지 알고싶습니다.
답변 3
1
네
위 소스를 보시면 maxAttempts를 2 를 설정한 것은 우리가 직접 RetryTemplate 빈을 생성할 때 정의한 값입니다.
즉 faultTolerant() 설정에서 별도의 설정을 하지 않는다면 스프링 배치가 초기화 되면서 생성되는 RetryTemplate retryLimit 의 기본 maxAttempts 값은 0 입니다.
순서로 보면 예외가 발생할 경우 스프링 배치의 RetryTemplate 이 먼저 실행되고 그 다음 RetryItemProcess2 에 선언된 RetryTemplate 가 실행됩니다.
@Bean
public Step step1() throws Exception {
return stepBuilderFactory.get("step1")
.<String, Customer>chunk(5)
.reader(reader())
.processor(processor())
.writer(writer())
.faultTolerant()
// .retry(RetryableException.class)
// .retryLimit(2)
// .skip(RetryableException.class)
// .skipLimit(2)
.build();
}
그런데 위 소스에서 retryLimit 은 주석으로 되어 있기 때문에 maxAttempts 값은 0입니다.
만약 위 설정에서 maxAttempts 값을 2 로 주었다면 스프링 배치의 기본 RetryTemplate 도 두번의 재시도를 할 것이고 우리가 직접 생성한 RetryTemplate 도 두번의 재시도를 하게 됩니다.
결론적으로 각 RetryTemplate 에 설정한 maxAttempts 의 값에 따라 재시도가 결정되며 순서는 스프링 배치의 기본 RetryTemplate 가 먼저 실행되고 그 다음 직접 설정한 RetryTemplate 가 실행된다는 점을 기억하시면 될 것 같습니다.
0
여기 소스에서 new DefaultRetryState(item, rollbackClassifier)를 추가했을 경우 입니다.
Retry(3) 강의 27:40에서 실행 하셨을때의 경우 입니다.
public class RetryItemProcessor2 implements org.springframework.batch.item.ItemProcessor<String, Customer> {
@Autowired
private RetryTemplate retryTemplate;
private int cnt = 0;
@Override
public Customer process(String item) throws Exception {
System.out.println("ItemProcessor : " + item);
Classifier<Throwable, Boolean> rollbackClassifier = new BinaryExceptionClassifier(true);
Customer customer = retryTemplate.execute(
new RetryCallback<Customer, RuntimeException>() {
@Override
public Customer doWithRetry(RetryContext retryContext) throws RuntimeException {
System.out.println("item = " + item);
if (item.equals("1") || item.equals("2")) {
cnt++;
throw new RetryableException("Retry Exception!! cnt : " + cnt);
}
return new Customer(item);
}
},
new RecoveryCallback<Customer>() {
@Override
public Customer recover(RetryContext retryContext) throws Exception {
return new Customer(item);
}
},
new DefaultRetryState(item, rollbackClassifier)
);
return customer;
}
}
@Configuration
@RequiredArgsConstructor
public class RetryTemplateConfiguration {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
private int chunkSize = 5;
@Bean
public Job job() {
return jobBuilderFactory.get("batchjob")
.incrementer(new RunIdIncrementer())
.start(step1())
.build();
}
@Bean
public Step step1() {
return stepBuilderFactory.get("step1")
.<String, Customer>chunk(chunkSize)
.reader(new ItemReader<String>() {
int i = 0;
@Override
public String read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
i++;
System.out.println("ItemReader :" + i);
return i > 10 ? null : String.valueOf(i);
}
})
.processor(retryItemProcessor())
.writer(System.out::println)
.faultTolerant()
// .skip(RetryableException.class)
// .skipLimit(2)
// .retry(RetryableException.class)
// .retryLimit(2)
.build();
}
@Bean
public ItemProcessor<? super String, Customer> retryItemProcessor() {
return new RetryItemProcessor2();
}
@Bean
public RetryTemplate retryTemplate() {
Map<Class<? extends Throwable>, Boolean> exceptionClasses = new HashMap<>();
exceptionClasses.put(RetryableException.class, true);
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
backOffPolicy.setBackOffPeriod(2000);
SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy(2, exceptionClasses);
RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setRetryPolicy(simpleRetryPolicy);
// retryTemplate.setBackOffPolicy(backOffPolicy);
return retryTemplate;
}
0