이 포스트는 이전의
Spring Batch로 특정 로직을 매 시간 실행해보자!
포스트의 연장선입니다.
이전에 Spring Batch로 cron을 설정하였습니다.
public void run() {
try {
// 더 나은 활용 방법은 https://jojoldu.tistory.com/490 이곳 침고
// 지금은 따로 쓰고있는 타입이 없어서 기본값으로 넣습니다!
JobParameters jobParameters = new JobParametersBuilder()
.toJobParameters();
jobLauncher.run(job, jobParameters);
} catch (Exception e) {
System.out.println(e);
}
}
이렇게 했는데 아래와 같은 로그가 뜨지 뭐에요?
Job: [SimpleJob: [name=updateHotVideoJob]] launched with the following parameters: [{}]
Step already complete or not restartable, so no action to execute: StepExecution: id=18, version=3, name=updateHotVideo, status=COMPLETED, exitStatus=COMPLETED, r...
Job: [SimpleJob: [name=updateHotVideoJob]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 17ms
요약하자면
따라서 Step을 재시작할 수 없기에 위와 같은 로그가 뜬 것입니다.
실제로 로그를 보더라도 EXECUTION
에는 ID가 74까지 있지만 EXECUTION PARAMS
에는 ID가 72까지 로깅되어있습니다. 즉 73, 74 ID는 실행되지 않았다는 소리죠. 이를 해결해봅시다!
Spring에서도 이를 추천하고있고, 이게 제일 간단합니다.
그냥 간단히 아래의 JobParamter에 값만 넣어주고 .addXXX
체이닝을 사용하여 JobParamter를 추가해주면 됩니다.
내부에서 쓰는 parameter가 거의 없다시피 하니 이렇게만 해줘도 문제 없습니다!
JobParameters jobParameters = new JobParametersBuilder()
.addLong(KEY, VALUE)
.toJobParameters();
jobLauncher.run(job, jobParameters);
하지만 실무에서는 이렇게 쓰기 보다는 paramter를 넣고 Step에서 이를 쓰게 하는 것이 더 좋겠죠?
Job이 실행될때마다 DB에 PARAMETER_VALUE
가 저장되는 것을 볼 수 있습니다. DB 조작이 일어난다는 얘기이고, 오버헤드가 발생한다는 의미이기도 합니다.
하나의 Job에 최소 1개의 column이 생성되므로 DB 조작에 따른 오버헤드가 발생합니다.
하지만 방법 2의 단점에 비하면 매우 작은 단점이라 무시해도 될 정도입니다. 수 ms마다 계속 실행되어야 하는 경우가 아니라면 크게 문제 없습니다.
Step 내부에서 .allowStartIfComplete(true)
체이닝을 사용하여 Step을 재사용하게 할 수도 있습니다.
return new StepBuilder("updateHotVideo", jobRepository)
.tasklet(tasklet, transactionManager)
.allowStartIfComplete(true)
.build();
하나의 Job 내부에 하나의 Step만 존재한다면 이 방식을 사용하여도 문제 없겠으나, 실제로는 아래와 같이 step이 여러 개 있는 경우가 대다수입니다.
return new JobBuilder("updateMemberProfileJob", jobRepository)
.start(firstStep)
.next(secondStep)
.next(clearStep)
.build();
만약 step이 더 많아진다면 관리하기가 더 어렵겠죠? 그래서 Spring에서는 1번 방법을 권장하고 있습니다.
매우 빠른 시간동안 여러 번 job이 실행되어야 하는 경우에는 방법 2를, 일반적인 상황에서는 방법 1을 사용하는 것이 좋습니다.
어차피 Job 자체는 @Bean
이라 싱글톤으로 동작하고, 내부에서는 거의 안바뀌거든요.
반은 맞는 질문이고 반은 틀린 질문입니다. Job Instance가 새롭게 만들어지는 경우는 아래와 같습니다.
변경될 때
RunIdIncrementer
를 상속받아 무조건 증가하라고 로직을 만들었을 때그 외에는 해당 Job을 실행하지 않는다
가 원칙입니다. (JobInstanceAlreadyCompleteException
)
예외로, Job이 실패한 경우 재실행 정책에 따라 Job을 재시작 하든지 실패한 상태로 두든지 하겠죠? 재시작하면 JobExecution
만 재생성되고 Instance는 재생성되지 않습니다.
네! 해결 됐습니다! parameter를 다른 값으로 주면 새로 생성하고 이를 실행하는 모습을 볼 수 있습니다!