Spring Batch 핵심 설정: JobLauncher와 JobRepository 커스터마이징

안녕하세요. 

Spring Batch를 단순히 ‘쓰는’ 단계를 넘어 ‘설계’하는 단계가 되면, 필연적으로 건드려야 하는 두 가지 빈(Bean)이 있습니다.
바로 배치를 실행하는 녀석(JobLauncher)저장하는 녀석(JobRepository)입니다.

기본 설정을 그대로 써도 되지만, “배치를 비동기로 실행하고 싶다”거나 “트랜잭션 격리 수준을 바꾸고 싶다”면 이 둘을 커스터마이징해야 합니다.


1. JobLauncher: 동기 vs 비동기

기본적으로 JobLauncher동기(Synchronous) 방식입니다. 즉, 배치가 끝날 때까지 요청한 스레드(main이나 HTTP 요청 스레드)가 대기합니다.

하지만 웹 API를 통해 배치를 실행시켰는데, 배치가 1시간 동안 돈다면? 클라이언트는 타임아웃 에러를 받게 될 겁니다. 이럴 때 비동기(Asynchronous) 실행이 필요합니다.

비동기 JobLauncher 설정

@Configuration
public class BatchConfig {

    @Bean
    public JobLauncher asyncJobLauncher(JobRepository jobRepository) throws Exception {
        TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher();
        jobLauncher.setJobRepository(jobRepository);
        // 핵심: 비동기 TaskExecutor 설정
        jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor());
        jobLauncher.afterPropertiesSet();
        return jobLauncher;
    }
}

이렇게 설정된 asyncJobLauncher를 주입받아 run()을 호출하면, 배치는 별도 스레드에서 돌고 run() 메서드는 즉시 JobExecution 객체를 반환하며 리턴됩니다. (ExitStatus는 ‘UNKNOWN’ 상태로 반환됨)


2. JobRepository: 메타 데이터 저장소

JobRepository는 배치의 모든 실행 이력(CRUD)을 담당합니다. Spring Boot가 자동으로 만들어주지만, 트랜잭션 매니저나 격리 수준을 조정해야 할 때가 있습니다.

커스텀 JobRepository 설정 (Spring Batch 5)

Spring Batch 5부터는 BatchConfigurer를 상속받는 방식이 아니라, 직접 빈을 등록하는 방식이 권장됩니다.

@Configuration
public class BatchRepoConfig {

    @Bean
    public JobRepository jobRepository(DataSource dataSource, PlatformTransactionManager transactionManager) throws Exception {
        JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
        factory.setDataSource(dataSource);
        factory.setTransactionManager(transactionManager);

        // 1. 격리 수준 변경 (기본값: SERIALIZABLE)
        // 성능을 위해 READ_COMMITTED로 낮추는 경우가 많음
        factory.setIsolationLevelForCreate("ISOLATION_READ_COMMITTED");

        // 2. 테이블 접두사 변경
        factory.setTablePrefix("SYSTEM_BATCH_");

        factory.afterPropertiesSet();
        return factory.getObject();
    }
}

왜 격리 수준을 낮추나요?

기본값인 SERIALIZABLE은 데이터 정합성은 완벽하지만, 락(Lock)을 심하게 잡습니다. 여러 배치가 동시에 돌거나, 짧은 주기로 실행될 때 메타 테이블 경합으로 인한 데드락이나 타임아웃이 발생할 수 있습니다. 이를 완화하기 위해 실무에서는 READ_COMMITTED를 많이 사용합니다.


3. 요약 및 활용 전략

  • JobLauncher:
    • 기본: CLI에서 실행하거나, 순차적으로 실행할 때 사용.
    • 비동기: 웹 Admin 페이지에서 “배치 실행” 버튼을 누르고 바로 응답을 줘야 할 때 사용.
  • JobRepository:
    • 기본: 대부분의 경우 그대로 사용.
    • 커스텀: DB 락 문제가 발생하거나, 메타 테이블 이름을 바꿔야 할 때 튜닝.

이 두 가지를 자유자재로 다룰 수 있다면, 여러분은 Spring Batch의 ‘엔진’을 튜닝할 줄 아는 엔지니어입니다.

관련 글 보기