Spring Batch를 썼는데 배치 실행이 안돼요

HanSH·2025년 7월 3일
0

SpringBoot 삽질기

목록 보기
12/12

이 포스트는 이전의 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

요약하자면

  1. Step이 이미 종료되었다.
  2. Step이 재시작 불가능하게 생성되었다.

따라서 Step을 재시작할 수 없기에 위와 같은 로그가 뜬 것입니다.

실제로 로그를 보더라도 EXECUTION에는 ID가 74까지 있지만 EXECUTION PARAMS에는 ID가 72까지 로깅되어있습니다. 즉 73, 74 ID는 실행되지 않았다는 소리죠. 이를 해결해봅시다!

방법 1. Parameter를 전달

Spring에서도 이를 추천하고있고, 이게 제일 간단합니다.

장점

  1. 재시작 정책의 유연성
    • 실패한 Job에 대해서만 재시작 할 수 있게 하므로 정책 설정이 유연합니다.
  2. 명확한 Job Instance 관리
    • 각 실행이 별개의 Instance로 동작하기 떄문에 성공/실패 확인이 편합니다.

그냥 간단히 아래의 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마다 계속 실행되어야 하는 경우가 아니라면 크게 문제 없습니다.

방법 2. Step에서 재사용 가능하도록 변경

장점

  1. DB 오버헤드 감소
    • JobParameter를 주지 않더라도
  2. 특정 Step만 재시작 가능

단점

  1. 재시작할 Step을 어떻게 판별할 것인가?
    • 이전의 Step에 연계되어 실행되는 Step일 수 있는데, 이걸 재시작하겠다고..?

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이라 싱글톤으로 동작하고, 내부에서는 거의 안바뀌거든요.

그러면 왜 Parameter를 주면 새로운 Job Instance가 생성되나요?

반은 맞는 질문이고 반은 틀린 질문입니다. Job Instance가 새롭게 만들어지는 경우는 아래와 같습니다.

  1. Parameter의 값이 변경될 때
    • 이전 Job이 성공하였고, 이전과는 다른 Parameter Value를 사용한 경우 새로운 Instance가 생성됩니다.
    • Job Parameter로 같은 값을 주면 Job을 실행하지 않아요!
  2. RunIdIncrementer를 상속받아 무조건 증가하라고 로직을 만들었을 때
    • 1번의 Parameter가 수정된 것과 동일한 동작을 합니다.
  3. Job을 최초 실행할 경우
    • 이전에 실행한 Job이 없으니 무조건 한번은 실행합니다.

그 외에는 해당 Job을 실행하지 않는다가 원칙입니다. (JobInstanceAlreadyCompleteException)
예외로, Job이 실패한 경우 재실행 정책에 따라 Job을 재시작 하든지 실패한 상태로 두든지 하겠죠? 재시작하면 JobExecution만 재생성되고 Instance는 재생성되지 않습니다.

그래서 해결 됐나요?


네! 해결 됐습니다! parameter를 다른 값으로 주면 새로 생성하고 이를 실행하는 모습을 볼 수 있습니다!

profile
저는 말하는 싹 난 감자입니다

0개의 댓글