[SpringBatch 실습] 12. preventRestart() 지정에 따른 수행 과정 파악하기

반응형
728x90
반응형

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

 

[SpringBatch 실습] 13. incrementer 설정하기, JobParametersIncrementer 를 구현하여 커스텀 설정하기

incrementer() 사용 이유를 알아보자. Job 생성 package com.project.springbatch._20_incrementer; import lombok.RequiredArgsConstructor; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframewor

devfunny.tistory.com

 

이렇게 추가하면 계속해서 증가되는 식별자가 파라미터에 추가되어 재실행하여도 같은 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이 재수행된다.

 

 

 

반응형

Designed by JB FACTORY