Documents

Spring Batch

컴포넌트

batch stereotypes

Job

  • 하나의 배치 작업을 정의하는 개념

Job Launcher

  • JobParameters를 이용하여 Job을 실행함

  • 실행 결과를 JobRepository에, 실행 중인 Job에서 JobExecution에 정보를 제공함

Job Parameters

  • Job을 시작하는데 사용되는 파라미터

Step

  • Job에 대한 순차적인 처리 단계

  • 하나의 Job은 여러 Step을 가질 수 있음

Chunk-oriented Processing, Chunk 지향 처리

한 번에 하나씩 데이터를 읽어와 Chunk로 만든 뒤 Chunk 단위로 트랜잭션을 다루는 것을 의미한다. (실패할 경우에 Chunk 단뤼로 롤백한다) 즉, Reader와 Processor에서는 1건씩 다뤄지고, Writer에선 Chunk 단위로 처리된다.

Chunk-oriented Processing

Item Reader

Item Processor

Item Writer

Tasklet

  • Step에서 실행되는 작업

  • Chunk 지향 처리를 기본으로 제공

  • Tasklet을 별도로 구현하여 사용하는 것이 가능 → 개발자가 Step에서 하고 싶은 내용을 자유롭게 작성 가능

  • Tasklet 구현을 통해 작성 가능

    public class SimpleTasklet implements Tasklet {
        @Override
        public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
            // todo
            return RepeatStatus.FINISHED;
        }
    }
  • StepExecutionListener 구현을 통해 실행 전/후 작업 가능

    public class SimpleTasklet implements Tasklet, StepExecutionListener {
        @Override
        public void beforeStep(StepExecution stepExecution) {
            // before
        }
    
        @Override
        public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
            // todo
            return RepeatStatus.FINISHED;
        }
    
        @Override
        public ExitStatus afterStep(StepExecution stepExecution) {
            // after
            return ExitStatus.COMPLETED;
        }
    }

메타 테이블

BATCH_JOB_INSTANCE

배치가 정상적으로 수행되면 인스턴스 정보를 기록한다. 이 때, jobParameter 에 따라 실행되므로 중복된 jobParameter 를 전달받으면 실행되지 않는다. jobParameter 는 아래와 같이 전달할 수 있다.

java -jar batch.jar --spring.batch.job.name=simpleJob param1=true param2=123

코드내에서 jobParameter 를 아래와 같이 가져올 수 있다.

@Slf4j
@RequiredArgsConstructor
@Configuration
public class SimpleJobConfiguration {
    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

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

    @Bean
    public Step simpleStep1() {
        return stepBuilderFactory.get("simpleStep1")
            .tasklet((contribution, context) -> {
                log.info("{}", context.getStepContext().getJobParameters()); (1)
            })
            .build();
    }

    @Bean
    @JobScope
    public Step simpleStep2(@Value("#{jobParameters[params1]}") Boolean params1) {
        return stepBuilderFactory.get("simpleStep2")
            .tasklet((contribution, context) -> {
                log.info("{}", params1); (2)
            })
            .build();
    }
}
1 Context에서 jobParameter 가져오기
2 spring batch scope 선언으로 파라미터를 통해 jobParameter 가져오기
3 어플리케이션 실행시 jobParameter 의 할당되는 것이 아니므로, null 을 넣어주더라도 job 실행시에 파라미터가 주입된다

String Batch에는 @StepScope@jobScope 가 있다. @StepScope 를 String Batch 컴포넌트(Tasklet, ItemReader, ItemWriter, ItemProcessor)에 사용하면 Step의 실행시점에 해당 컴포넌트를 Spring Bean으로 생성한다. 또한, @JobScope 는 Job 실행시점에 Spring Bean을 생성한다. 즉, 빈을 어플리케이션 생성 시점이 아닌 scope가 실행되는 시점에 생성하도록 해준다.

jobParameter 중복 이슈를 우회하는 방법

job을 실행할 때 동일한 jobParameter 를 사용하면 아래와 같은 에러를 만나게 된다.

Caused by: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={-job.name=simpleJob, params1=true}.  If you want to run this job again, change the parameters.

이를 해결하는 방법으로는 매번 jobParameter 를 다르게 주는 것인데 개발 도중에 매번 값을 변경해주는 것이 여간 귀찮은 것이 아니다.
JobBuilderFactoryincrementer 설정을 통해 해결할 수도 있다.

@Bean
public Job simpleJob() {
    return jobBuilderFactory.get("simpleJob")
        .start(simpleStep1())
        .next(simpleStep2(null))
        .incrementer(new RunIdIncrementer()) (1)
        .build();
}
1 jobParameter 를 출력하면 run.id=1 과 같이 run.id 가 추가된 것을 볼 수 있다. 이를 통해서 jobParameter 의 중복을 회피한다.

RunIdIncrementer 는 동일 파라미터로 Job을 실행할 때 중복 에러를 방지하려고 사용하는 클래스인 것을 알고 있어야 한다. 그러므로 jobParameter가 바뀌더라도 전에 실행했던 파라미터로 덮어쓰게 된다. RunIdIncrementer 를 사용하면서 파라미터를 유지하려면 다른 방식을 사용해야 한다.

⇒ 값이 변경되는 것은 반영이 되는데, 값을 제거하면 이전 값이 주입된다.

JobParameter

  • JobParameter로 받을 수 있는 타입은 Date, Double, Long, String 이다.

    • Date 보단 String 으로 받아서 LocalDate 로 변경해서 사용하자.

BATCH_JOB_EXECUTION

Job이 정상적으로 수행됬는지, 실패됬는지에 대한 정보를 기록한다.

BATCH_JOB_EXECUTION_PARAMS

애플리케이션을 실행시킬 때 전달한 Job Parameter 정보를 기록한다.

필요한 bean만 로드하기

@ConditionalOnProperty 어노테이션을 통해서 필요한 빈만 로드하기

@ConditionalOnProperty(name = "job.name", havingValue = SampleJobConfig.JOB_NAME) (1)
1 job.name 은 실행시킬 job 이름을 저장하는 값이다. spring.batch.job.name 을 사용할 수도 있다.
2 job.name 프로퍼티에 SampleJobConfig.JOB_NAME 이 있을 경우에 해당 컴포넌트를 생성하는 어노테이션이다.