preventRestart()
1) 선언하지 않는 경우 - true
@Bean
public Job preventRestartJob() {
return this.jobBuilderFactory.get("preventRestartJob")
/* step start */
.start(preventRestartStep1())
.next(preventRestartStep2())
.build();
}
2) 선언하는 경우 - false
@Bean
public Job preventRestartJob() {
return this.jobBuilderFactory.get("preventRestartJob")
/* step start */
.start(preventRestartStep1())
.next(preventRestartStep2())
.preventRestart() // false
.build();
}
3) false로 지정하는 경우 - false
@Bean
public Job preventRestartJob() {
return this.jobBuilderFactory.get("preventRestartJob")
/* step start */
.start(preventRestartStep1())
.next(preventRestartStep2())
.preventRestart(false) // false
.build();
}
Job 생성
PreventRestartJobConfiguration.java
package com.project.springbatch._19_preventRestart;
import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/*
--job.name=preventRestartJob
*/
@Configuration
@RequiredArgsConstructor
public class PreventRestartJobConfiguration {
// job 생성
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
@Bean
public Job preventRestartJob() {
return this.jobBuilderFactory.get("preventRestartJob")
/* step start */
.start(preventRestartStep1())
.next(preventRestartStep2())
.build();
}
@Bean
public Step preventRestartStep1() {
return stepBuilderFactory.get("preventRestartStep1")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("preventRestartStep1");
return RepeatStatus.FINISHED;
}
})
.build();
}
@Bean
public Step preventRestartStep2() {
return stepBuilderFactory.get("preventRestartStep2")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("preventRestartStep2");
throw new RuntimeException("step2 fail");
//return RepeatStatus.FINISHED;
}
})
.build();
}
}
1) preventRestart() 선언하지 않는다.
@Bean
public Job preventRestartJob() {
return this.jobBuilderFactory.get("preventRestartJob")
/* step start */
.start(preventRestartStep1())
.next(preventRestartStep2())
.build();
}
선언하지 않았을 경우, default로 true 값을 가진다.
2) Step2를 고의로 에러를 발생시키자.
@Bean
public Step preventRestartStep2() {
return stepBuilderFactory.get("preventRestartStep2")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("preventRestartStep2");
throw new RuntimeException("step2 fail");
//return RepeatStatus.FINISHED;
}
})
.build();
}
실행
preventRestart() = true인 경우
첫번째 실행 결과
java.lang.RuntimeException: step2 fail
DB 테이블 조회
1) BATCH_JOB_EXECUTION
COLUMN | VALUE |
STATUS | FAILED |
EXIT_CODE | FAILED |
JOB_EXECUTION_ID | 4 |
2) BATCH_JOB_INSTANCE
COLUMN | VALUE |
JOB_NAME | preventRestartJob |
3) BATCH_STEP_EXECUTION
- preventRestartStep1
COLUMN | VALUE |
STEP_NAME | preventRestartStep1 |
EXIT_CODE | COMPLETED |
STATUS | COMPLETED |
JOB_EXECUTION_ID | 4 |
- preventRestartStep2
COLUMN | VALUE |
STEP_NAME | preventRestartStep1 |
EXIT_CODE | FAILED |
STATUS | FAILED |
JOB_EXECUTION_ID | 4 |
두번째 실행
위 preventRestartStep1, preventRestartStep2 스텝 중에서 preventRestartStep2가 실패했었기 때문에 preventRestartStep1은 실행되지 않고 preventRestartStep2만 실행된다.
preventRestartStep2
java.lang.RuntimeException: step2 fail
preventRestart() = false인 경우
@Bean
public Job preventRestartJob() {
return this.jobBuilderFactory.get("preventRestartJob")
/* step start */
.start(preventRestartStep1())
.next(preventRestartStep2())
.preventRestart() // false
.build();
}
동일한 파라미터로, 동일한 Job 실행시 아래와 같은 JobRestartException 에러가 발생한다.
org.springframework.batch.core.repository.JobRestartException: JobInstance already exists and is not restartable
지금 위 코드로는, preventRestart() 를 정확하게 테스트할 수 없다. 다음의 코드를 추가하자.
.incrementer(new RunIdIncrementer())
incrementer() 포스팅 바로가기
https://devfunny.tistory.com/790
이렇게 추가하면 계속해서 증가되는 식별자가 파라미터에 추가되어 재실행하여도 같은 JOB으로 인식하지 않는다.
1) 기존 데이터 삭제
기존에 수행했던 DB 데이터를 삭제 후 다시 수행해보자.
2) 코드 추가
@Bean
public Job preventRestartJob() {
return this.jobBuilderFactory.get("preventRestartJob")
/* step start */
.start(preventRestartStep1())
.next(preventRestartStep2())
.incrementer(new RunIdIncrementer())
.preventRestart() // default : true, preventRestart() : false, preventRestart(false) : false
.build();
}
incrementer() 추가 후 첫번째 수행
첫번째 실행 결과
java.lang.RuntimeException: step2 fail
DB 테이블 조회
1) BATCH_JOB_EXECUTION
COLUMN | VALUE |
STATUS | FAILED |
EXIT_CODE | FAILED |
JOB_EXECUTION_ID | 4 |
2) BATCH_JOB_INSTANCE
COLUMN | VALUE |
JOB_NAME | preventRestartJob |
3) BATCH_STEP_EXECUTION
- preventRestartStep1
COLUMN | VALUE |
STEP_NAME | preventRestartStep1 |
EXIT_CODE | COMPLETED |
STATUS | COMPLETED |
JOB_EXECUTION_ID | 4 |
- preventRestartStep2
COLUMN | VALUE |
STEP_NAME | preventRestartStep1 |
EXIT_CODE | FAILED |
STATUS | FAILED |
JOB_EXECUTION_ID | 4 |
재수행
이때가 중요하다. 결과 로그를 보자.
preventRestartStep1
preventRestartStep2
java.lang.RuntimeException: step2 fail
preventRestartStep1 이 다시 수행되었다. 분명 위에서 첫번째 수행시, preventRestartStep1 는 COMPLETED 상태로 완료되었는데 preventRestart()가 false 였기 때문에 preventRestartStep1 부터 모든 스텝이 재수행된 것이다.
precentRestart() 값 | 수행 |
true (default) | 실패한 STEP부터 재수행된다. |
false | 모든 STEP이 재수행된다. |