본문 바로가기
스프링/만들면서 배우는 실무 백엔드 개발

13. SpringBatch 5 + Kotlin 적용하기

by kdohyeon (김대니) 2023. 7. 16.
반응형

spring batch

2022년 하반기에 SpringBoot 3.0 이 릴리즈 되었고 많은 변화가 있었습니다. (내용)
기본 Java 버전이 17 으로 올라갔고, SpringBatch 버전도 5 로 올라갔습니다.
이번 시간에는 SpringBatch 5 를 적용한 사례를 공유하고자 합니다.
What's New in Spring Batch 5


SpringBatch 의존성 주입

SpringBatch 와 h2 데이터베이스 의존성을 주입한다.

implementation("org.springframework.boot:spring-boot-starter-batch")
implementation("com.h2database:h2")

SpringBatchApplication 생성

배치잡은 실행이 되고 자동으로 종료되어야 하니 exitProcess 를 실행시켜준다.

@SpringBootApplication
class CryptoLabsBatchApplication

fun main(args: Array<String>) {
    val runApplication = runApplication<CryptoLabsBatchApplication>(*args)
    exitProcess(SpringApplication.exit(runApplication))
}

SpringBatch 설정 (Config.)

@BatchDataSource 어노테이션으로 배치용 DataSource 를 설정해주고, 데이터베이스는 H2 를 사용한다.
(이 설정 부분을 놓쳐서 계속 배치잡이 정상적으로 동작하지 않았었다.)

@Configuration
class BatchJobConfig {
    @Bean("batchDataSource")
    @BatchDataSource
    fun batchDataSource(): DataSource = EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
        .addScript("/org/springframework/batch/core/schema-h2.sql")
        .generateUniqueName(true).build()
}

특정 스프링배치 잡만 실행시키기 위해서는 아래처럼 application.yml 파일도 설정해줘야 한다. 만약 해주지 않을 경우에는 등록된 모든 배치 잡이 실행되게 된다.

# application.yml
spring:
  batch:
    job:
      names: ${job.name:NONE}

배치잡 생성 (Batch Configuration)

이 배치잡의 역할은 특정 UseCase 를 호출하는 단순 Tasklet 이다.

@Configuration
class FetchUpbitCandleBatchConfiguration(
    private val sendCandleMessageUseCase: SendCandleMessageUseCase,
) {

    private val logger = logger()

    companion object {
        const val JOB_NAME = "fetchUpbitCandleBatchJob"
        const val STEP_NAME = "${JOB_NAME}_step"
    }

    @Bean
    fun job(jobRepository: JobRepository, platformTransactionManager: PlatformTransactionManager): Job {
        logger.info { "$JOB_NAME 을 시작합니다." }
        return JobBuilder(JOB_NAME, jobRepository)
            .preventRestart()
            .start(step(jobRepository, platformTransactionManager))
            .incrementer(RunIdIncrementer())
            .build()
    }

    @Bean
    fun step(jobRepository: JobRepository, platformTransactionManager: PlatformTransactionManager): Step {
        return StepBuilder(STEP_NAME, jobRepository)
            .tasklet({ _, _ ->
                val command = UpbitMinuteCandleSearchCommand(MarketPair.KRW_BTC.value, 1, 10);
                sendCandleMessageUseCase.publishMinuteCandle(command)
                RepeatStatus.FINISHED
            }, platformTransactionManager)
            .build()
    }
}

Job 과 Step 을 각각 스프링 빈으로 등록해준다.
JobRepository 와 PlatformTransactionManager 를 주입받을 수 있도록 한다.

 

어려웠던 점

SpringBatch 4 와 5 버전의 큰 차이점 중 하나는 TransactionManager 를 명시적으로 사용하는지에 대한 유무이다. SpringBatch 4 버전에서는 JobBuilderFactory 와 StepBuilderFactory 를 사용해서 따로 TransactionManager 를 작성하지 않아도 알아서 동작했던 반면, SpringBatch 5 에서는 명시적으로 사용해야 하는 것 같다. 관련 내용
이런 부분들을 쉽게 풀어보고자 SpringBatch 5 에서는 DefaultBatchConfiguration 을 사용하라고 안내하는데, 작동이 잘 되듯 하면서 잘 안되는 부분들이 있었다. Job, Step 은 기대했던 것처럼 정상 동작했지만 Tasklet 이 실행되지 않았다.
구글에 내용을 찾아보니 비슷한 경험을 한 글들이 있었고, 해당 글에서는 DefaultBatchConfiguration 을 따로 사용하지 않았다. 관련 내용 1, 관련 내용 2
결국 나도 DefaultBatchConfiguration 을 사용하지 않고, @BatchDataSource 등 별도로 설정해서 해결했다.

느낀 점

사실 아직 뭐가 더 좋아졌는지 체감이 안되어서 SpringBatch 5 를 꼭 써야겠다! 라는 생각은 잘 안든다. 새로운 버전을 사용해본다 정도..?

반응형

댓글