Spring Batch 실행 중 오류가 main()
까지 전달되지 않는 문제와 NOOP 상태(All steps already completed or no steps configured for this job.
) 발생 문제를 해결하는 방법을 정리합니다.
자동 실행(Spring Boot spring.batch.job.enabled=true
)과 수동 실행(spring.batch.job.enabled=false
후 JobLauncher
직접 호출) 방식에 맞게 정리하였습니다.
1. Spring Batch 오류 전파 문제
문제 상황
- Spring Batch 실행 중 Job이 실패했지만
main()
까지 예외가 전달되지 않는 문제가 발생할 수 있습니다. Pod
또는애플리케이션 모니터링 시스템
이 Batch Job이 실패했음을 감지하려면,System.exit(1);
을 호출하여 비정상 종료 상태를 전달해야 합니다.- 또는 예외를 던져서
main()
에서 감지해야 합니다.
2. 자동 실행 (spring.batch.job.enabled=true
)에서 오류 전파
설정 방법
application.properties
에서 자동 실행을 활성화해야 합니다.
spring.batch.job.enabled=true
해결 방법: JobExecutionListener
에서 오류 감지
Spring Batch는 기본적으로 spring.batch.job.enabled=true
설정 시 자동 실행됩니다.
이 경우, JobExecution을 직접 감지하여 오류 로그를 남길 수 있습니다.
샘플 코드: JobExecutionListener
에서 오류 감지
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class LoggingJobExecutionListener implements JobExecutionListener {
private static JobExecution lastJobExecution;
@Override
public void afterJob(JobExecution jobExecution) {
lastJobExecution = jobExecution;
if (!jobExecution.getExitStatus().getExitCode().equals("COMPLETED")) {
log.error("
Job Failed: {}", jobExecution.getExitStatus().getExitDescription());
}
}
public static JobExecution getLastJobExecution() {
return lastJobExecution;
}
}
이제 Batch Job이 실패하면 로그로 오류가 출력됨.
오류를
main()
에서 감지하려면 JobExecutionListener
만으로는 부족하며 main()
에서 직접 확인해야 함.
자동 실행에서 오류 전파를 위한 main()
구성
import org.springframework.batch.core.JobExecution;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
public class BatchApplication {
public static void main(String[] args) {
int exitCode = 1;
try {
SpringApplicationBuilder builder = new SpringApplicationBuilder(BatchApplication.class);
ConfigurableApplicationContext context = builder.run(args);
JobExecution jobExecution = LoggingJobExecutionListener.getLastJobExecution();
System.out.println("Job Execution ID: " + jobExecution.getId());
System.out.println("Exit Code: " + jobExecution.getExitStatus().getExitCode());
exitCode = SpringApplication.exit(context);
if (!jobExecution.getExitStatus().getExitCode().equals("COMPLETED")) {
exitCode = 1; //
Job 실패 시 exitCode 설정
throw new RuntimeException("Batch Job Failed: " + jobExecution.getExitStatus().getExitDescription());
}
System.exit(exitCode);
} catch (Exception e) {
System.err.println("
Batch Job 실행 중 예외 발생: " + e.getMessage());
e.printStackTrace();
System.exit(exitCode);
}
}
}
이제 자동 실행 상태에서도 오류가
main()
까지 전달되며, 실패 시 exitCode
가 1로 설정됨.
3. 수동 실행 (spring.batch.job.enabled=false
)에서 오류 전파
설정 방법
application.properties
에서 자동 실행을 비활성화해야 합니다.
spring.batch.job.enabled=false
해결 방법: JobLauncher
를 직접 실행하여 오류 감지
자동 실행을 비활성화한 후 JobLauncher
를 직접 실행하는 경우,
Job 실행 후 JobExecution
의 결과를 확인하고 RuntimeException
을 던져 main()
까지 오류를 전달해야 합니다.
샘플 코드: main()
에서 JobLauncher 직접 실행 후 오류 감지
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
public class BatchApplication {
public static void main(String[] args) {
int exitCode = 1;
try {
SpringApplicationBuilder builder = new SpringApplicationBuilder(BatchApplication.class);
ConfigurableApplicationContext context = builder.run(args);
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job job = context.getBean("sampleJob", Job.class);
JobParameters jobParameters = new JobParameters(); // 실행할 JobParameters 설정
JobExecution jobExecution = jobLauncher.run(job, jobParameters);
System.out.println("Job Execution ID: " + jobExecution.getId());
System.out.println("Exit Code: " + jobExecution.getExitStatus().getExitCode());
exitCode = SpringApplication.exit(context);
if (!jobExecution.getExitStatus().getExitCode().equals("COMPLETED")) {
exitCode = 1; //
Job 실패 시 exitCode 설정
throw new RuntimeException("Batch Job Failed: " + jobExecution.getExitStatus().getExitDescription());
}
System.exit(exitCode);
} catch (Exception e) {
System.err.println("
Batch Job 실행 중 예외 발생: " + e.getMessage());
e.printStackTrace();
System.exit(exitCode);
}
}
}
이제 Job 실행 후 실패하면
RuntimeException
을 던지고 System.exit(1)
이 호출됨. Pod에서 Crash 상태로 감지될 수 있음.
4. Spring Batch NOOP
상태 해결 방법
문제: All steps already completed or no steps configured for this job.
Spring Batch는 동일한 JobParameters
를 사용하면 기존 실행 기록을 재사용하기 때문에 Job이 실행되지 않고 NOOP
상태가 됩니다.
해결 방법 1: JobParameters
에 timestamp
추가 (추천)
JobParameters jobParameters = new JobParametersBuilder()
.addLong("timestamp", System.currentTimeMillis()) //
매 실행마다 새로운 JobInstance 생성
.toJobParameters();
JobExecution jobExecution = jobLauncher.run(job, jobParameters);
이제
timestamp
값이 변경되므로, JobInstance가 새롭게 생성되어 실행됨. 더 이상
NOOP
상태가 발생하지 않고, Job이 실행됨.
해결 방법 2: RunIdIncrementer
사용
@Bean
public Job sampleJob(JobRepository jobRepository, Step sampleStep, PlatformTransactionManager transactionManager) {
return new JobBuilder("sampleJob", jobRepository)
.incrementer(new RunIdIncrementer()) //
실행할 때마다 새로운 JobInstance 생성
.start(sampleStep)
.build();
}
이제
RunIdIncrementer
가 자동으로 실행 ID를 증가시키므로, 같은 JobParameters
를 사용해도 중복 실행 가능! 이제
main()
에서 JobLauncher.run(job, new JobParameters());
해도 NOOP
발생하지 않음.
자동 실행 vs 수동 실행 오류 전파 비교 정리
실행 방식 | spring.batch.job.enabled 값 | 오류 전파 방법 | NOOP 해결 방법 |
---|---|---|---|
자동 실행 (Spring Boot 기본) | true | main() 에서 exitCode = 1; 설정 후 RuntimeException 발생 | RunIdIncrementer() 사용하여 JobParameters 변경 |
수동 실행 (JobLauncher 직접 호출) | false | main() 에서 exitCode = 1; 설정 후 RuntimeException 발생 | JobParameters 에 timestamp 추가 |
이제 자동 실행과 수동 실행에 따라 오류를
main()
까지 전달할 수 있습니다!