Spring Boot 3.x, Spring Batch 5 환경에서 cli에서 --job.name으로 지정한 batch job 실행하기

smallcherry's techlog·2023년 10월 23일
3

글 작성 계기

  • 팀에서 배치 서버 실행을 기존 cron job으로 실행하다가 유지 보수 및 관리 편의성 때문에 Jenkins를 통해 실행하려 했는데 어떤 job을 실행할 지 수행 시점에 결정하기 좋은, cli 로 batch job을 지정, 실행하는 작업이 필요했다.

문제 해결 과정

문제 상황

  • 구글링 결과 application.yml에 spring.batch.job.name값을 지정해주고, 실행 argument로 --job.name=Job1 과 같이 지정하여 실행하면 별도의 설정 없이 원하는 job을 cli상 argument로 지정하여 실행하는 게 가능하다고 하고, 별도의 지정을 해주지 않으면 Bean으로 등록된 모든 job들이 실행된다고 하는데, 아무리 실행시켜봐도 JOB_INSTANCE 테이블에 아무 데이터도 쌓이지 않았다.
  • 팀 코드는 물론, 따로 생성한 데모 프로젝트에서도 어떠한 job도 실행되지 않았다.

버전 확인

  • 문득 내가 참고한 jojoldu님의 SpringBatch 관련 글(https://jojoldu.tistory.com/328)이 2018년에 작성되었다는 점과, Springboot 3이 작년 말에 릴리즈 되었다는 점이 불안해졌다.
  • 역시나, 우리 프로젝트는 springboot 3.x.x 버전을 사용중이지만, jojoldu님 블로그 속 build.gradle 파일은 springboot 2.x.x 버전을 가리키고 있었다...

그래서 왜 안됐던 건데?

  1. @EnableBatchProcessing 이라는 어노테이션은 Springboot2.x.x 까지 BatchAutoConfiguration에 등록된 빈들을 자동으로 등록해주는 역할을 하였지만, Springboot 3.x.x 부터는 (@EnableBatchProcessing라는 어노테이션이 없음 && DefaultBatchConfiguration이 존재하지 않음)일때만 경우만 BatchAutoConfiguration이 활성화 된다.
@ConditionalOnMissingBean(value = DefaultBatchConfiguration.class, annotation = EnableBatchProcessing.class)
public class BatchAutoConfiguration {
/** 이하 생략 */
  1. 이 BatchAutoConfiguration 내부에서 정의해주는 jobLauncherApplicationRunner에서 job.name으로 지정된 job 이름을 jobName으로 지정 시켜주는 역할을 하게 된다. 기존 프로젝트에서는 직접 jobLauncher.run 코드를 통해 job을 실행하고 있어서 정상 동작이 가능했다.
public class BatchAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnProperty(prefix = "spring.batch.job", name = "enabled", havingValue = "true", matchIfMissing = true)
	public JobLauncherApplicationRunner jobLauncherApplicationRunner(JobLauncher jobLauncher, JobExplorer jobExplorer,
			JobRepository jobRepository, BatchProperties properties) {
		JobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(jobLauncher, jobExplorer, jobRepository);
		String jobNames = properties.getJob().getName();
		if (StringUtils.hasText(jobNames)) {
			runner.setJobName(jobNames);
		}
		return runner;
	}
  1. 본 프로젝트에서는 transactionManager, batchDataSource의 별도 지정을 위해 각각의 JobConfig 파일에 @EnableBatchProcessing 어노테이션을 사용 중이라서, 1에서 언급된 BatchAutoConfiguration의 활성화 조건을 어겼다. 그 이유로 BatchAutoConfiguration 내부에 정의된 jobLauncherApplicationRunner이 bean으로 등록되지 못하여, job을 실행할 runner가 없어서, 어떤 job도 실행되지 않았던 것이다.

해결 과정

  • 일단 jobLauncherApplicationRunner bean을 등록해주어야 원하는 job을 실행 argument로 받아 실행할 수 있으므로, 기존 dataSource, batchDataSource, transactionManager가 등록되어있던 BatchConfig 파일에 아래와 같이 jobLauncherApplicationRunner bean을 등록하였다.
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "spring.batch.job", name = "enabled", havingValue = "true", matchIfMissing = true)
    public JobLauncherApplicationRunner jobLauncherApplicationRunner(JobLauncher jobLauncher, JobExplorer jobExplorer,
                                                                     JobRepository jobRepository, BatchProperties properties, Collection<Job> jobs) {
        JobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(jobLauncher, jobExplorer, jobRepository);
        String jobNames = properties.getJob().getName();
        if (StringUtils.hasText(jobNames)) {
            if (jobs.stream().map(Job::getName).noneMatch(s -> s.equals(jobNames))){
                throw new IllegalArgumentException(jobNames + "는 등록되지 않은 job name입니다. job name을 확인하세요.");
            }
            runner.setJobName(jobNames);
        }
        return runner;
    }

새로 등록하는 김에, 기존 BatchAutoConfiguration에 등록된 jobLauncherApplicationRunner 빈 정의 코드에, 존재하지 않는 jobname을 요청하는 경우 예외를 반환하는 코드도 추가하였다.

이후 아래와 같이 job name을 지정하고 job Parameter를 정의하여 실행하니, 잘 실행되는 것을 확인할 수 있었다.

성공 실행 로그

2023-10-23T16:05:33,993 INFO  [restartedMain] o.s.b.c.l.s.SimpleJobLauncher$1: Job: [SimpleJob: [name=shortsStatisticsJob]] completed with the following parameters: [{'requestDate':'{value=20231023134022, type=class java.lang.String, identifying=true}'}] and the following status: [COMPLETED] in 73ms

고찰

  1. 코드 속에 답이 있다. BatchAutoConfiguration에 붙은 @ConditionalOnMissingBean(value = DefaultBatchConfiguration.class, annotation = EnableBatchProcessing.class) 어노테이션과 그 옵션 값들의 의미를 알았다면, 코드만 보고 답을 찾을 수 있었을 것이다. 결국 구글링(https://europani.github.io/spring/2023/06/26/052-spring-batch-version5.html)을 통해 원인을 찾아낼 수 있었지만.
  2. 항상 버전을 잘 확인하자. 아무리 신뢰 가능한 좋은 글이라도 맹신하지 말고 버전을 늘 확인하자.
  3. 문제가 되는 상황을 규명하고 해결할 수 있었던 이유는, 결국 원인 분석이었다. 문제를 해결할 때 아래 순서로 가보도록 노력하자.
    1. 원하는 바를 구체적인 How to로 구글링 (Spring Batch 에서 job name을 프로그램 argument로 받아서 실행하는 방법)
    2. 적용이 잘 되지 않는 경우, 문제 상황과 해결방안을 구글링 (spring batch에서 job이 실행되지 않는 이유 / job을 실행하는 방법 / spring batch job을 cli로 실행하는 법)
    3. 2의 결과가 잘 나오지 않거나 문제 상황 자체가 잘 규명되지 않는 경우, 왜 되지 않는 것인지 다양한 각도로 분석하고 구글링 (1의 구글링 자료와 프로젝트 간 스프링 부트 버전 차이를 파악 -> springboot 3.x.x 버전에서는 @EnableBatchProcessing 어노테이션이 있을 때 BatchAutoConfiguration이 비활성화 된다는 사실 파악 -> 이것이 job이 실행되지 않는 이유였음을 깨닫기)
    4. 문제의 원인이 되는 상황 해소 및 해결 방안 구글링

결국 내가 습득한 지식과 해결한 방식 모두 전부 구글링을 통해 나오는 자료들에 있었지만,
내 프로젝트의 어떤 점이 문제인지 파악하고, 그를 해소하기 위해 적용하는 데에 많은 시간을 쏟았다.

이 시간을 줄이는 것이 <문제 해결 능력이 뛰어난> 개발자가 되기 위한 관건일 것 같다..
문제를 해결하는 과정을 계속해서 회고하고 고찰을 적어보는 습관을 길러야겠다.

Reference

https://umbum.dev/1238/

https://chaibin0.tistory.com/entry/Spring-Batch-50-%EB%B2%84%EC%A0%84-%EC%A0%81%EC%9A%A9%ED%96%88%EB%8D%94%EB%8B%88-%EC%8B%A4%ED%96%89%EB%90%98%EC%A7%80-%EC%95%8A%EB%8A%94%EB%8D%B0%EC%9A%94

https://europani.github.io/spring/2023/06/26/052-spring-batch-version5.html

profile
Java Developer

0개의 댓글

관련 채용 정보