SpringBoot 안쓰는 경우 - CommandLineJobRunner

 

Configuring and Running a Job

Because the script launching the job must kick off a Java Virtual Machine, there needs to be a class with a main method to act as the primary entry point. Spring Batch provides an implementation that serves just this purpose: CommandLineJobRunner. It’s i

docs.spring.io

 

 

SpringBoot 쓰는 경우 - yml 이용한 세팅

 

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;
	}
  • SpringBoot 3 기준, BatchAutoConfiguration에서 JobLauncherApplicationRunner를 Bean으로 등록해준다.
  • SpringBoot 2 까지는 spring.batch.job.enabled=false로 만들어야 jobName을 누락하는 경우 전체 job 실행되지 않았던 것 같은데, SpringBoot 3 부터는 spring.batch.job.enabled=true여도 jobName 누락하더라도 전체 job이 실행되지 않는다. 옵션을 true로 놓아도 무방하다.
Caused by: java.lang.IllegalArgumentException: Job name must be specified in case of multiple jobs
	at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.validate

 

어째서인지 BatchAutoConfiguration으로 자동으로 Bean이 생성되지 않는다.

원인은 ? Spring Boot 3 부터 @EnableBatchProcessing를 붙이면 auto-config 기능이 비활성화 되기 때문 !

Spring Boot 2와 정반대로, 애너테이션을 없애야 auto-config가 적용되어 Bean이 생성된다.

 

JobLauncherApplicationRunner에 알 수 없는 job name을 넘겨도 배치가 실패하지 않는다.

따라서 별도 PostConstructor를 이용해 검사하거나, 아예 JobLauncherApplicationRunner 빈 자체를 직접 생성하면서 검사하는 것이 좋아보인다. 요구사항을 만족하는 빈을 직접 생성하기로 했다.

 

직접 JobLauncherApplicationRunner Bean 생성

요구사항

  • JobParameter 목록에 현재시각을 자동으로 추가해주어야 한다.
  • cli에서 key1=value1 key2=value2 형식으로 잡파라미터 받을 수 있어야 한다.
  • 알 수 없는 job name이 들어왔을 때, 실패해야 한다. (ExitCode도 비정상 반환)
  • 배치 중간에 실패했을 때, 애플리케이션 ExitCode를 비정상으로 반환해야 한다.

 

 

@EnableConfigurationProperties(BatchProperties::class)
@Configuration
class JobLauncherApplicationRunnerConfig {

    @Bean
    fun jobLauncherApplicationRunner(
        jobLauncher: JobLauncher, jobExplorer: JobExplorer, jobRepository: JobRepository,
        properties: BatchProperties, jobs: Collection<Job>
    ): JobLauncherApplicationRunner {
        val runner = JobLauncherApplicationRunner(jobLauncher, jobExplorer, jobRepository)
        val jobName = properties.job.name

        if (!jobs.map { it.name }.contains(jobName)) {
            logger.error { "### job Bean [$jobName] 찾을 수 없음" }
            throw IllegalArgumentException("### job Bean [$jobName] 찾을 수 없음")
        }

        runner.setJobName(jobName)
        return runner
    }
}
@SpringBootApplication
class MyBatchApplication

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

위와 같이 세팅하면 요구사항을 만족 할 수 있다.

 

contribution

이런 기능은 아예 JobLauncherApplicationRunner에서 제공해주는게 좋아보여 이슈를 올렸는데.

https://github.com/spring-projects/spring-boot/issues/35940

 

JobLauncherApplicationRunner returns a success exit code even when no jobs have been run. · Issue #35940 · spring-projects/spr

When using JobLauncherApplicationRunner, if we pass an arbitrary JobName, the spring application terminates with a success exit code without failure. If the job name is entered incorrectly by mista...

github.com

갑자기 나타난 인도인이 PR을 먼저 올리면서 그 친구가 담당해서 처리하게 되었다...;; (PR을 보니 contribution이 무지 하고싶었나봄... Author에 자기 이름도 넣어두고. 그래그래 이해한다 ㅎ)

 

아무튼 잘 처리해 주시길...

 

 

Test시에는 어떻게?

https://www.baeldung.com/spring-junit-prevent-runner-beans-testing-execution