WEB/Spring Batch

스프링 배치 실행 - Step

Tony Lim 2023. 2. 28. 12:55
728x90

StepBuilderFactory

 

1. StepBuilderFactory

- StepBuilder를 생성하는 팩토리 클래스로서 get(String name) 메서드 제공

- StepBuilderFactory.get("stepName")으로 Step을 생성함

 

2. StepBuilder

- Step을 구성하는 설정 조건에 따라 다섯 개의 하위 빌더 클래스를 생성하고 실제 Step 생성을 위임한다.

- TaskletStepBuilder = TaskletStep을 생성하는 기본 빌더 클래스

- SimpleStepBuilder = TaskletStep을 생성하며 내부 저긍로 청크기반의 작업을 처리하는 ChunkOrientedTasklet 클래스를 생성

- PartitionStepBuilder = PartitionStep을 생성하며 멀티 스레드 방식으로 Job을 실행

- JobStepBuilder = JobStep을 생성하여 Step 안에서 Job을 실행

- FlowStepBuilder = FlowStep을 생성하여 Step 안에서 Flow를 실행

StepBuilder에서 제공되는 여러 종류의 API를 통해서 하위 구체적인 ~StepBuilder에게 위임하게 된다.

 


TaskletStep - 개념 및 API 소개

 

1. 기본개념

- 스프링 배치에서 제공하는 Step 의 구현체로서 Tasklet을 실행시키는 도메인 객체

- RepeatTemplate를 사용해서 Tasklet의 구문을 트랜잭션 경계 내에서 반복해서 실행함

- Task 기반과 Chunk 기반으로 나누어서 Tasklet을  실행함

 

2. Task vs Trunk 기반 비교

- 스프링 배치에서 Step의 실행단위는 크게 2가지로 나뉨

-- chunk 기반

--- 하나의 큰덩어리를 n개 씩 나눠서 실행한다는 의미로 대량처리를 하는 경우 효과적으로 설계됨

--- ItemReader , ItemProcessor, ItemWriter를 사용하며 청크 기반 전용 Tasklet인 ChunkOrientedTasklet 구현체가 제공된다.

-- Task 기반

--- ItemReader와 ItemWriter와 같은 청크 기반의 작업보다 단일 작업 기반으로 처리되는 것이 더 효율적인 경우

--- 주로 Tasklet 구현체를 만들어 사용

--- 대량 처리를 하는 경우 chunk 기반에 비해 더 복잡한 구현 필요


TaskletStep - tasklet()

 

1. 기본 개념

- Tasklet 타입의 클래스를 설정한다.

-- Tasklet

- step내에서 구성되고 실행되는 도메인 객체로서 주로 단일 태스크를 수행하기 위한 것

- TaskletStep에 의해 반복적으로 수행되며 반환값에 따라 계속 수행중 혹은 종료한다.

- RepeatStatus - Tasklet 의 반복 여부 상태 값

  • RepeatStatus.FINISHED - Tasklet 종료 , RepeatStatus 을 null 로 반환하면 RepeatStatus.FINISHED 로 해석됨
  • RepeatStatus.CONTINUABLE - Tasklet 반복
  • RepeatStatus.FINISHED가 리턴되거나 실패 예외가 던져지기 전까지 TaskletStep 에 의해 while 문 안에서 반복적으로 호출 됨 (무한루프 주의)

- 익명 클래스 혹은 구현 클래스를 만들어서 사용한다.

- 이 메소드를 실행하게 되면 TaskletStepBuilder가 반환되어 관련 API를 설정할 수 있다.

- Step 에 오직 하나의 Tasklet 설정이 가능하며 두개 이상의 설정 했을 경우 마지막에 설정한 객체가 실행된다.

 


TaskletStep - startLimit() / allowStartIfComplete()

 

startLimit()

1. 기본 개념

- Step 의 실행 횟수를 조정할 수 있다.

- Step 마다 설정할 수 있다.

- 설정 값을 초과해서 다시 실행하려고 하면 StartLimitExceedException이 발생

- start-limit 의 디폴트 값은 Integer.MAX_VALUE

 

 allowStartIfComplete()

1. 기본개념

- 재시작 가능한 job에서 Step 의 이전 성공 여부와 상관없이 항상 step을 실행하기 위한 설정

- 실행마다 유효성을 검증하는 Step이나 사전 작업이 꼭 필요한 Step등

- 기본적으로 COMPLETED 상태를 가진 Step 은 Job 재 시작시 실행하지 않고 스킵한다.

- allow-start-if-complete 가 "true" 로 설정된 step은 항상 실행한다.

 


TaskletStep 아키텍처

각 객체가 실행이 될때 중간 중간 생성 및 실행되는 것(StepExecution) 들을 확인하면 된다.

StepListener를 통해 befroeStep, afterStep등을 설정하여 특정시점에 호출하게 만들어줄 수 있다.

  • AbstractStep#execute 메소드에서 이뤄진다.
getCompositeListener().beforeStep(stepExecution);
...
doExecute(stepExecution);
...
exitStatus = exitStatus.and(getCompositeListener().afterStep(stepExecution));

Tasklet이 끝났을때 특별한 응답값을 주지않으면 null 이 return 되는데 FINISHED와 같은의미로 해석됨

 


JobStep

 

1. 기본개념

- Job 에 속하는 Step 중 외부의 Job을 포함하고 있는 Step

- 외부의 Job이 실패하면 해당 Step이 실패하므로 결국 최종 기본 Job도 실패한다

- 모든 메타데이터는 기본 Job과 외부 Job 별로 각각 저장된다

- 커다란 시스템을 작은 모듈로 쪼개고 job의 흐름을 관리하고자 할때 사용할 수 있다

 

ParentJob 안의 JobStep 안에 ChildJob이 step1을 가지고 있고 또한 step2를 가지고 있다.
즉 ParentJob이 가진 Step은 JobStep, Step2 를 가지고 있다고 볼수 있다.

ChildJob의 step1 이 실패하면 ParentJob은 자신의 step이 실패한것이니까 최종적으로 실패하게 된다. 물론 ChildJob도 실패 한다. (JobExecution 에서)

ParentJob의 step2 가 실패하게되면 ChildJob은 성공했다고 나오지만 ParentJob만 실패했다고 Jobexecution table에 저장이 된다.
Step execution 테이블에도 jobStep ,step1 은 성공 , step는 실패가 나오게 된다.

@RequiredArgsConstructor
@Configuration
public class JobStepConfiguration {

    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job parentJob() {
        return this.jobBuilderFactory.get("parentJob")
                .start(jobStep(null))
                .next(step2())
                .build();
    }
    @Bean
    public Step jobStep(JobLauncher jobLauncher) {
        return this.stepBuilderFactory.get("jobStep")
                .job(childJob())
                .launcher(jobLauncher)
                .listener(new StepExecutionListener() {
                    @Override
                    public void beforeStep(StepExecution stepExecution) {
                        stepExecution.getExecutionContext().putString("name", "user1");
                    }

                    @Override
                    public ExitStatus afterStep(StepExecution stepExecution) {
                        return null;
                    }
                })
                .parametersExtractor(jobParametersExtractor())
                .build();
    }
    @Bean
    public Job childJob() {
        return this.jobBuilderFactory.get("childJob")
                .start(step1())
                .build();
    }
    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1")
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
//                        throw new RuntimeException("step1 was failed");
                        return RepeatStatus.FINISHED;
                    }
                })
                .build();
    }
    @Bean
    public Step step2() {
        return stepBuilderFactory.get("step2")
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        throw new RuntimeException("step2 was failed");
//                        return RepeatStatus.FINISHED;
                    }
                })
                .build();
    }

    @Bean
    public DefaultJobParametersExtractor jobParametersExtractor() {
        DefaultJobParametersExtractor extractor = new DefaultJobParametersExtractor();
        extractor.setKeys(new String[]{"name"});
        return extractor;
    }
}

JOB_EXECUTION_PARAMS 테이블에서 116이 childJob에 해당하는 것이다. ParentJob의 ExecutionParams 도 물려 받았고 DefaultJobParametersExtractor를 통해 beforeStep listener에서 추가한 key, value값을 주입받을 수 있었던것이다.

 

728x90

'WEB > Spring Batch' 카테고리의 다른 글

스프링 배치 청크 프로세스 이해  (2) 2023.03.22
스프링 배치 실행 - Flow  (0) 2023.03.03
스프링 배치 실행 - Job  (0) 2023.02.23
스프링 배치 도메인 이해  (0) 2023.02.17
스프링 배치 소개 + 시작  (0) 2023.02.16