Programming-[Backend]/SpringBoot

[TIL] Spring Batch, Scheduling, k8s cronJob

컴퓨터 탐험가 찰리 2025. 9. 22. 21:26
728x90
반응형

 

spring batch와 k8s cronJob 인프라를 통해 주기적으로 API 요청을 하고 DB 데이터들을 분석하는 기능을 만들었다. 이에 대해 간략하게 나마 정리해둔다.

 

Spring Batch 구조

크게 Job -> Step -> Tasklet/Chunk 구조로 작동한다.

 

Job은 최상위 단위이며 하나 이상의 Step으로 구성된다. Spring Batch 라이브러리를 build에 넣고 실행하면 DB상에 Batch 관련 테이블들이 생기는데, 여기서 JOB_EXECUTION 관련된 테이블에 Job 실행 내역들이 기록된다. 실행 시마다 JobInstance가 생성된다.

 

Step은 Job 하위에 있는 단계이다. Tasklet 기반은 파일 삭제, API 호출 등의 단일 작업 단위이며, Chunk는 DB에서 읽고 가공하여 저장하는 등의 대량 데이터를 처리하는 단위이다.

 

Reader, Processor, Writer 구성이 있으며 각각 데이터를 읽어들이고, 가공하거나 검증하고, 저장하는 역할을 한다. commit-interval 마다 트랜잭션 단위로 실행된다.

 

# 팁

내 경우 spring batch의 enabled 설정을 off로 처리했다.그리고 하나의 소스 코드에서 Program argument를 해석하여 하나의 Runner가 인자를 통해 여러 개의 Job을 실행할 수 있도록 했다.

 

다시 말해 Runner를 아래처럼 구성했다.

@Slf4j
@Component
@RequiredArgsConstructor
public class BatchStartupRunner implements ApplicationRunner {

    private final JobLauncher jobLauncher;
    private final ApplicationContext applicationContext;
    private final ConfigurableApplicationContext configurableApplicationContext;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        List<String> jobNames = args.getNonOptionArgs();

        if (jobNames.isEmpty()) {
            log.error("Job name is required. Available jobs: pagingUpdateJob, adGroupTransmitJob");
        }

        for (String jobName : jobNames) {
            try {
                Job job = (Job) applicationContext.getBean(jobName);

 

여기서 args.getNonOptionArgs()는 자바 프로그램을 실행할 때 COMMAND 인자로 주는 값이다. 또는 Intellij에서 아래처럼 Run Configuration에서 줄 수 있는 Program argument다.

 

그리고 이 값으로 jobName을 준다. 아래처럼 Config에서 등록한 Bean의 이름으로 jobName을 해석하여 해당 job을 실행하게 한다.

@Slf4j
@Configuration
@RequiredArgsConstructor
public class AdGroupTransmitJobConfig {

    private final AdGroupTransmitTasklet adGroupTransmitTasklet;

    @Bean
    public Job adGroupTransmitJob(JobRepository jobRepository, Step adGroupTransmitStep) {
        return new JobBuilder("adGroupTransmitJob", jobRepository)
                .start(adGroupTransmitStep)
                .build();
    }

    @Bean
    public Step adGroupTransmitStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        return new StepBuilder("adGroupTransmitStep", jobRepository)
                .tasklet(adGroupTransmitTasklet, transactionManager)
                .build();
    }
}

 

 

이렇게 하면 동일한 소스코드에서 Tasklet이나 Chunk를 여러 개 만들고, k8s CronJob에서 인자만 바꿔가면서 실행하면 된다. 만약 Spring Batch의 enabled 설정이 true라면 빈이 중복된다는 에러가 뜬다.

 

 

 

또한, k8s CronJob에서 반드시 Job을 끝내면 ExitStatus를 반환하거나 아래 코드처럼 exit()을 호출하여 서버를 종료시켜줘야한다. 

// 모든 Job 완료 후 정상 종료
log.info("All batch jobs completed successfully. Shutting down application.");
int exitCode = SpringApplication.exit(configurableApplicationContext, () -> 0);
System.exit(exitCode);

 

그래야 프로세스가 다운되고 사용했던 resource가 반환되면서 k8s의 노드 자원이 회복된다.

728x90
반응형