기존에 스케줄러에서 jobLauncher.run(job, jobParameters)
을 실행했을때 잡의 이름같은것을 선택하지도 않았는데 동작하는것을 보고 의문이 들어서 찾아봤다.
@Autowired lateinit var job: Job
을 이용하면 모든 job이 실행여러개의 job을 등록할때엔 @Bean에 name을 설정해주어야 한다.
MyBatchConfig.kts
@Configuration
class MyBatchConfig(
private val entityManagerFactory: EntityManagerFactory,
) {
companion object {
const val chuckSize = 3
const val JOB_NAME = "MY_JOB"
const val STEP_NAME = "MY_STEP"
}
@Bean(name = [JOB_NAME])
fun myJob(jobRepository: JobRepository, @Qualifier("MY_STEP") step: Step): Job {
return JobBuilder("myJob", jobRepository)
.start(step)
.build()
}
@Bean(name = [STEP_NAME])
fun myStep(jobRepository: JobRepository, transactionManager: PlatformTransactionManager, entityManagerFactory: EntityManagerFactory): Step {
return StepBuilder("myStep", jobRepository)
.chunk<Member, String>(chuckSize, transactionManager)
.reader(reader(null))
.processor(processor(null))
.writer(writer(null))
.build()
}
@Bean
@StepScope // Bean의 생성 시점이 스프링 애플리케이션이 실행되는 시점이 아닌 @JobScope, @StepScope가 명시된 메서드가 실행될 때까지 지연
// jobParameters 사용하려면 필요
fun reader(@Value("#{jobParameters[requestDate]}") requestDate: String?): JpaPagingItemReader<Member> {
println("==> reader: $requestDate")
return JpaPagingItemReaderBuilder<Member>()
.name("reader")
.entityManagerFactory(entityManagerFactory)
.pageSize(chuckSize)
.queryString("SELECT m FROM Member m")
.build()
}
@Bean
@StepScope
fun processor(@Value("#{jobParameters[requestDate]}") requestDate: String?): ItemProcessor <Member, String> {
println("==> processor: $requestDate")
return ItemProcessor<Member, String> { item: Member ->
item.name
}
}
@Bean
@StepScope
fun writer(@Value("#{jobParameters[requestDate]}") requestDate: String?): ItemWriter<String> {
println("==> writer: $requestDate")
return ItemWriter<String> { items ->
for (item in items) {
println("name: $item")
}
}
}
}
OtherBatchConfig.kts
@Configuration
class OtherBatchConfig(
private val entityManagerFactory: EntityManagerFactory,
): DefaultBatchConfiguration() {
companion object {
const val chuckSize = 3
const val JOB_NAME = "OTHER_JOB"
const val STEP_NAME = "OTHER_STEP"
}
@Bean(name = [JOB_NAME])
fun otherJob(jobRepository: JobRepository, @Qualifier("OTHER_STEP") step: Step): Job {
return JobBuilder("otherJob", jobRepository)
.start(step)
.build()
}
@Bean(name = [STEP_NAME])
fun otherStep(jobRepository: JobRepository, transactionManager: PlatformTransactionManager, entityManagerFactory: EntityManagerFactory): Step {
return StepBuilder("otherStep", jobRepository)
.chunk<Member, String>(chuckSize, transactionManager)
.reader(otherReader(null))
.processor(otherProcessor(null))
.writer(otherWriter(null))
.build()
}
@Bean
@StepScope
fun otherReader(@Value("#{jobParameters[requestDate]}") requestDate: String?): JpaPagingItemReader<Member> {
println("==> reader: $requestDate")
return JpaPagingItemReaderBuilder<Member>()
.name("reader")
.entityManagerFactory(entityManagerFactory)
.pageSize(chuckSize)
.queryString("SELECT m FROM Member m")
.build()
}
@Bean
@StepScope
fun otherProcessor(@Value("#{jobParameters[requestDate]}") requestDate: String?): ItemProcessor <Member, String> {
println("==> processor: $requestDate")
return ItemProcessor<Member, String> { item: Member ->
item.name
}
}
@Bean
@StepScope
fun otherWriter(@Value("#{jobParameters[requestDate]}") requestDate: String?): ItemWriter<String> {
println("==> writer: $requestDate")
return ItemWriter<String> { items ->
for (item in items) {
println("name: $item")
}
}
}
JobRegistry
와 JobRegistryBeanPostProcessor
설정을 해주고 실행하고싶은 잡 이름을 설정했다.
MyScheduler.kts
@EnableScheduling
@Component
class MyScheduler(
private val jobRegistry: JobRegistry,
private val jobLauncher: JobLauncher
) {
@Bean
fun jobRegistryBeanPostProcessor(): JobRegistryBeanPostProcessor {
val postProcessor = JobRegistryBeanPostProcessor()
postProcessor.setJobRegistry(jobRegistry)
return postProcessor
}
@Scheduled(fixedDelay = 30000)
fun startMyJob() {
println("======= my job ========")
val parameter = mapOf(
"requestDate" to JobParameter(OffsetDateTime.now().toString(), String::class.java),
"jobName" to JobParameter("myJob", String::class.java)
)
val jobParameters = JobParameters(parameter)
jobLauncher.run(jobRegistry.getJob("myJob"), jobParameters)
}
@Scheduled(fixedDelay = 50000)
fun startOtherJob() {
println("======= other job ========")
val parameter = mapOf(
"requestDate" to JobParameter(OffsetDateTime.now().toString(), String::class.java),
"jobName" to JobParameter("otherJob", String::class.java)
)
val jobParameters = JobParameters(parameter)
jobLauncher.run(jobRegistry.getJob("otherJob"), jobParameters)
}
}
my job과 other job 출력한게 잘 나와있는걸 확인할 수 있다.
BATCH_JOB_INSTANCE 테이블에도 실행된 job name이 기록되어 있다.
.
.
.
참고