[Spring Batch] Meta Data Table

minholee_93·2020년 3월 25일
0

Spring Batch

목록 보기
4/4
post-thumbnail

참고 자료 : https://jojoldu.tistory.com/326?category=902551


이번글에서는 앞서 생성한 Spring Batch의 Meta Data Table에 대해 자세히 알아보도록 하겠습니다.

1. Meta Data Table

이전글에서 생성한 spring batch meta data table의 전체 구조는 다음과 같습니다.

이번글에서는 위의 테이블들을 자세히 살펴보도록 하겠습니다. 😎

2. BATCH_JOB_INSTANCE

먼저 batch_job_instance 테이블은 job parameter에 따라 row가 생성되는 테이블 입니다.

현재 MySQL에서 batch_job_instance를 조회해보면 아래와 같이 검색됩니다.

• job_instance_id : batch_job_instance 테이블의 PK 입니다.

• job_name : 수행한 batch job의 name 입니다.

위와 같이 이전에 실행한 "simpleJob"이 있는 것을 확인할 수 있습니다.

이때 Job Parameter란 Spring Batch가 실행될때 외부에서 받을 수 있는 parameter 값으로 생각할 수 있습니다.

예를 들어, 특정 날짜를 job paramter로 넘기면 spring batch 에서는 해당 날짜 데이터로 조회/가공/입력 등의 작업을 할 수 있습니다.

이때 같은 batch job에 사용한 job parameter가 '다르면' batch_job_instance에 기록되지만, 만약 '같은' job paramter를 사용한 경우 기록되지 않습니다.

2-1) add job parameter

한번 확인해보겠습니다. 😎

아래와 같이 SimpleJobConifg를 변경합니다.

SimpleJobConfig

@Slf4j // log 사용을 위한 lombok 어노테이션
@RequiredArgsConstructor // 생성자 DI를 위한 lombok 어노테이션
@Configuration
public class SimpleJobConfig {
    private final JobBuilderFactory jobBuilderFactory; // 생성자 DI 받음
    private final StepBuilderFactory stepBuilderFactory; // 생성자 DI 받음

    @Bean
    public Job simpleJob(){
        return jobBuilderFactory.get("simpleJob")
                .start(simpleStep1(null))
                .build();
    }

    @Bean
    @JobScope
    public Step simpleStep1(@Value("#{jobParameters[requestDate]}") String requestDate){
        return stepBuilderFactory.get("simpleStep1")
                .tasklet((contribution, chunkContext) -> {
                    log.info(">>>>> This is Step1");
                    log.info(">>>>> requestDate = {}", requestDate);
                    return RepeatStatus.FINISHED;
                })
                .build();
    }
}

변경한 코드는 job parameter로 넘겨받은 requestDate 값을 로그에 출력시키는 기능입니다.

2-2) run batch with job parameter

위의 requestDate 값을 job parameter로 넘겨서 batch를 실행하기 위해선, program arguments에 해당값을 입력해야 합니다.

각자 본인의 IDE에서 설정창으로 이동합니다.

다음으로 program arguments에 'requestDate=20200325'와 같이 입력하면 됩니다.

저장 후 batch application을 실행하면 아래와 같이 job parameter가 전달되어 log 로 출력되는 것을 확인할 수 있습니다.

batch_job_instance를 확인하면 새로운 job instance row가 추가된 것을 확인할 수 있습니다.

2-3) duplicate job parameter

진짜로 job paramter가 같으면 새로운 batch_job_instance row가 생성되지 않을까요? 😅

같은 job parameter 값으로 batch applcation 을 실행해보면, 답을 확인할 수 있습니다.

같은 job parameter 값을 입력 후 batch를 실행하면 위와 같이 JobInstanceAlreadyCompleteException 에러가 발생하게되며

A job instance already exists and is complete for parameters={requestDate=20200325}.  If you want to run this job again, change the parameters.

동일 job을 실행시키고 싶다면 job parameter를 변경하라는 문구를 확인할 수 있습니다.

이때 job parameter를 변경해 실행해보면 아래와 같이 정상적으로 실행되며

batch_job_instance 테이블에도 정상적으로 row가 추가된 것을 확인할 수 있습니다.

즉, 동일한 Batch Job을 실행할때는 job parameter 값이 달라질때마다 batch_job_instance가 생성되게 됩니다.

3. batch_job_execution

batch_job_execution 테이블은 batch_job_instance와 부모-자식 관계에 있는 테이블로, batch_job_execution은 부모 batch_job_instance의 성공/실패한 모든 내역을 관리합니다.

현재 job_execution 테이블에는 3개의 row는

이전에 실행한 parameter가 없는 simpleJob, requestDate=20200325 parameter로 실행한 simpleJob, reqeustDate=20200326 parameter로 실행한 3개의 execution data 입니다.

이전의 모든 execution은 status가 completed로 성공한 job instance 였다는 것을 확인할 수 있습니다.

3-1) fail job

이번에는 batch job을 강제로 실패시킨뒤 job_execution 테이블에 어떻게 데이터가 insert 되는지 확인해보겠습니다.

아래와 같이 SimpleJobConfig를 변경합니다.

@Slf4j // log 사용을 위한 lombok 어노테이션
@RequiredArgsConstructor // 생성자 DI를 위한 lombok 어노테이션
@Configuration
public class SimpleJobConfig {
    private final JobBuilderFactory jobBuilderFactory; // 생성자 DI 받음
    private final StepBuilderFactory stepBuilderFactory; // 생성자 DI 받음

    @Bean
    public Job simpleJob(){
        return jobBuilderFactory.get("simpleJob")
                .start(simpleStep1(null))
                .next(simpleStep2(null))
                .build();
    }

    @Bean
    @JobScope
    public Step simpleStep1(@Value("#{jobParameters[requestDate]}") String requestDate){
        return stepBuilderFactory.get("simpleStep1")
                .tasklet((contribution, chunkContext) -> {
                    throw new IllegalArgumentException("step1에서 실패합니다.");
                })
                .build();
    }

    @Bean
    @JobScope
    public Step simpleStep2(@Value("#{jobParameters[requestDate]}") String requestDate){
        return stepBuilderFactory.get("simpleStep2")
                .tasklet((contribution, chunkContext) -> {
                    log.info(">>>>> This is Step2");
                    log.info(">>>>> requestDate = {}", requestDate);
                    return RepeatStatus.FINISHED;
                })
                .build();
    }
}

이번에는 job paramete를 requestDate=20200327로 변경해 실행시켜 보겠습니다.

의도한대로 batch job이 실패하는 것을 확인할 수 있습니다.

또한 batch_execution 테이블에는 status fail인 상태로 data가 insert 되는 것을 확인할 수 있습니다.

3-2) success job

이번에는 코드를 수정해 job을 성공시켜보겠습니다.

이전과 동일한 job parameter를 입력해 batch job을 실행해보면

job이 성공적으로 수행되는 것을 확인할 수 있습니다.

job_execution 테이블에도 정상적으로 data가 insert 되었습니다.

3-3) execution vs instance

위에서 뭔가 이상한것을 느끼시지 않았나요?

맞습니다. 동일한 job parameter로 동일한 job을 수행을 성공했습니다.

사실 spring batch는 동일한 job parameter로 '성공한 기록'이 있을때에만 재수행을 허용하지 않습니다.

또한 job_instance 테이블의 instance id가 job_execution 테이블에서는 여러번 나타날 수 있습니다.

위의 테이블을 자세히 보시면 성공했을때와 실패했을때 중복된 job_instance_id가 테이블의 값으로 insert 되어있는 것을 확인할 수 있습니다.

4. Summary

위의 내용을 간단히 그림으로 정리해보면 다음과 같습니다.

profile
Hello World 😎

0개의 댓글