[SpringBatch 실습] 16. ParentJob, ChildJob 관계 (JobStep 사용)

반응형
728x90
반응형

Job 생성

import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.*;
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.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.job.DefaultJobParametersExtractor;
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=parentJob
 */

@Configuration
@RequiredArgsConstructor
public class JobStepConfiguration {

    // job 생성
    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job parentJob() {
        return this.jobBuilderFactory.get("parentJob")
                .start(jobStep(null))
                .next(jobStepStep2())
                .build();
    }

    @Bean
    public Step jobStep(JobLauncher jobLauncher) {
        return stepBuilderFactory.get("jobStep")
                .job(childJob()) // 별도의 메타 job 으로 관리됨
                .launcher(jobLauncher)
                .parametersExtractor(jobParametersExtractor())
                .listener(new StepExecutionListener() {
                    @Override
                    public void beforeStep(StepExecution stepExecution) {
                        // jobParametersExtractor 에서 처리될 파라미터 저장
                        stepExecution.getExecutionContext().putString("name", "user1");
                    }

                    @Override
                    public ExitStatus afterStep(StepExecution stepExecution) {
                        return null;
                    }
                })
                .build();
    }

    private DefaultJobParametersExtractor jobParametersExtractor() {
        DefaultJobParametersExtractor extractor = new DefaultJobParametersExtractor();
        extractor.setKeys(new String[]{"name"}); // key
        return extractor;
    }

    @Bean
    public Job childJob() {
        return this.jobBuilderFactory.get("childJob")
                .start(jobStepStep1())
                .build();
    }

    @Bean
    public Step jobStepStep1() {
        return stepBuilderFactory.get("jobStepStep1")
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        System.out.println("jobStepStep1");
                       return RepeatStatus.FINISHED;
                    }
                })
                .build();
    }

    @Bean
    public Step jobStepStep2() {
        return stepBuilderFactory.get("jobStepStep2")
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        System.out.println("jobStepStep2");
                        return RepeatStatus.FINISHED;
                    }
                })
                .build();
    }
}

1) 수행 목록

parentJob
jobStep() 수행
jobStepStep2() 수행
jobStep childJob 수행
childJob jobStepStep1() 수행

 

2) jobStep()

Step에서 별도의 Job을 생성하고 실행한다.

@Bean
public Step jobStep(JobLauncher jobLauncher) {
    return stepBuilderFactory.get("jobStep")
            .job(childJob()) // 별도의 메타 job 으로 관리됨
            .launcher(jobLauncher)
    ...

}

 

3) jobParametersExtractor()

Step의 ExecutionContext를 Job이 실행되는데 필요한 JobParameters로 변환하는 방법을 정의한다. 

private DefaultJobParametersExtractor jobParametersExtractor() {
    DefaultJobParametersExtractor extractor = new DefaultJobParametersExtractor();
    extractor.setKeys(new String[]{"name"}); // key
    // name 에 해당하는 key 를 찾는다.
    // 그 key 에 해당하는 값들을 가져온다.
    return extractor; // user1
}

 

 

 

수행 순서

parentJob
jobStep() 수행
jobStepStep2() 수행
jobStep childJob 수행
childJob jobStepStep1() 수행

 

- Step 수행 순서

1) jobStepStep1() 수행
2) jobStepStep2() 수행

 

 

 

JobStepStep1() 실패시키기

@Bean
    public Step jobStepStep1() {
        return stepBuilderFactory.get("jobStepStep1")
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        System.out.println("jobStepStep1");
                        throw new RuntimeException("step1 was failed");
//                       return RepeatStatus.FINISHED;
                    }
                })
                .build();
    }

 

수행결과
java.lang.RuntimeException: step1 was failed

 

ChildJob이 실패하고, ChildJob이 실패함으로써 ParentJob도 실패하게된다.

 

 

 

DB 테이블 조회

1) BATCH_JOB_EXECUTION

JOB_EXECUTION_ID JOB_NAME STATUS EXIT_CODE
1 parentJob FAILED FAILED
2 childJob FAILED FAILED

 

2) BATCH_JOB_INSTANCE

COLUMN VALUE
1 parentJob
2 childJob

 

3) BATCH_STEP_EXECUTION

STEP_EXECUTION_ID STEP_NAME JOB_EXECUTION_ID STATUS EXIT_CODE
1 jobStep 1 FAILED FAILED
2 jobStepStep1 2 FAILED FAILED

 

1. jobStep 오류 메시지

java.lang.RuntimeException: step1 was failed

 

2. jobStepStep1 오류 메시지

org.springframework.batch.core.UnexpectedJobExecutionException: 
Step failure: the delegate Job failed in JobStep.

 

 

 

JobStepStep1() 성공 / JobStepStep2() 실패시키기

@Bean
    public Step jobStepStep2() {
    return stepBuilderFactory.get("jobStepStep2")
            .tasklet(new Tasklet() {
                @Override
                public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                    System.out.println("jobStepStep2");
                    throw new RuntimeException("step1 was failed");
                    // return RepeatStatus.FINISHED;
                }
            })
            .build();
}

 

수행결과
java.lang.RuntimeException: step2 was failed

 

위 실패한 jobStepStep2()를 수행시키는 Job은 ParentJob이다.

ParentJob은 실패하고, JobStepStep1()을 수행하는 ChildJob은 성공한다.

 

ParentJob의 Step을 통해 수행된 ChildJob이 실패했으므로 ParentJob도 실패가 되는 것이고, ParentJob만 실패했을 경우에는 ChildJob은 독립적으로 성공할 수 있다.

 

 

 

DB 테이블 조회

1) BATCH_JOB_EXECUTION

JOB_EXECUTION_ID JOB_NAME STATUS EXIT_CODE
3 parentJob FAILED FAILED
4 childJob COMPLETED COMPLETED

 

2) BATCH_JOB_INSTANCE

COLUMN VALUE
1 parentJob
2 childJob

 

3) BATCH_STEP_EXECUTION

STEP_EXECUTION_ID STEP_NAME JOB_EXECUTION_ID STATUS EXIT_CODE
3 (childJob) jobStep 4 COMPLETED COMPLETED
4 (parentJob) jobStepStep1 3 COMPLETED COMPLETED
5 (parentJob) jobStepStep2 3 FAILED FAILED

 

 

 

 

반응형

Designed by JB FACTORY