[Spring Batch] 메타 테이블 구조와 잡 중복 실행 관리

AIR·2025년 2월 17일

메타 테이블에서 잡 중복 실행 방지


Spring Batch의 메타 테이블은 다음과 같이 6개의 테이블로 구성된다.

  • BATCH_JOB_INSTANCE: Batch Job의 생성 정보 저장
  • BATCH_JOB_EXECUTION: Batch Job의 실행 정보 저장
  • BATCH_JOB_EXECUTION_PARAM: Batch Job에서 사용되는 파라미터 저장
  • BATCH_JOB_EXECUTION_CONTEXT: Batch Job 작업 중 사용되는 모든 정보가 기록되는 Context 저장
  • BATCH_STEP_EXECUTION: Batch Step의 실행 정보 저장
  • BATCH_STEP_EXECUTIOIN_CONTEXT: Batch Step에서 사용되는 모든 정보가 기록되는 Context 저장

여기서 잡의 중복 실행을 방지해주는 테이블은 BATCH_JOB_INSTANCE인데 이 테이블은 Job Parameter에 따라 생성되는 테이블이다.

이때 Job Parameter는 Spring Batch가 실행될 때 외부에서 받을 수 있는 파라미터다. 예를 들어 특정 날짜를 Job Parameter로 넘기면 Spring Batch에서는 해당 날짜 데이터로 조회/가공/입력 등의 작업을 할 수 있다.

BATCH_JOB_INSTANCE 테이블 구조

CREATE TABLE BATCH_JOB_INSTANCE (
    JOB_INSTANCE_ID BIGINT NOT NULL PRIMARY KEY,
    VERSION BIGINT,
    JOB_NAME VARCHAR(100) NOT NULL,
    JOB_KEY VARCHAR(32) NOT NULL,
    CONSTRAINT JOB_INST_UN UNIQUE (JOB_NAME, JOB_KEY)
) ENGINE=InnoDB;
  • JOB_NAME: 배치 작업의 이름을 저장
  • JOB_KEY: 작업 파라미터를 기반으로 생성된 해시 값으로, 동일한 작업 이름과 파라미터 조합에 대해 유일한 값을 가짐

JOB_NAMEJOB_KEY 컬럼은 유니크 제약 조건을 가지며 이를 통해 동일한 작업 이름과 파라미터 조합으로는 새로운 작업 인스턴스가 생성되지 않아 중복 실행이 방지된다.

즉, 같은 Batch Job이라도 Job Parameter가 다르면 BATCH_JOB_INSTANCE에 저장되며, Job Parameter가 같으면 저장되지 않고 JobInstanceAlreadyCompleteException를 터트리게 된다.


동일한 파라미터로 중복 실행을 하려면?


RunIdIncrementer

다음과 같이 현재 시간을 파라미터로 작업을 실행시킬 때 시간을 분 단위로 받는다면 매 요청마다 초 단위 차이가 나지만 중복 실행 방지에 의해 실행이 되지 않게 된다.

@GetMapping("/run-job")
public void runJob(@RequestParam("jobName") String jobName) throws Exception {

    Job job = jobRegistry.getJob(jobName);
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm");
    String date = dateFormat.format(new Date());

	JobParameters jobParameters = new JobParametersBuilder()
            .addString("date", date)
            .toJobParameters();
    jobLauncher.run(job, jobParameters);
}

Spring Batch에서는 동일한 파라미터로 작업을 재실행하고자 할 때 RunIdIncrementer를 사용할 수 있다. 이는 내부적으로 run.id라는 파라미터를 자동으로 증가시켜 매 실행마다 고유한 파라미터를 생성한다.

@Bean
public Job paymentJob(JobRepository jobRepository, Step paymentStep) {
    return new JobBuilder(JOB_NAME, jobRepository)
            .start(paymentStep)
            .incrementer(new RunIdIncrementer())
            .build();
}

하지만 RunIdIncrementer를 설정했더라도, 작업 실행 시 명시적으로 새로운 파라미터를 제공하지 않거나, 이전 실행 기록이 없는 경우 run.id가 생성되지 않을 수 있다. 따라서 JobLauncher를 통해 작업을 실행시킬 때 JobParametersBuildergetNextJobParameters 옵션을 통해 이전 실행 기록을 조회하여 새로운 파라미터를 생성할 수 있다. 그러면 내부적으로 JobParametersIncrementer을 이용해 자동으로 run.id 값을 설정해준다.

JobParameters jobParameters = new JobParametersBuilder(jobExplorer)
        .getNextJobParameters(job)
        .addString("date", date)
        .toJobParameters();
jobLauncher.run(job, jobParameters);

테스트

1분 내에 연속해서 잡을 실행시켜보면 동일한 시간의 파라미터인데도 독립적으로 잡 인스턴스가 생성된 것을 볼 수 있다.

BATCH_JOB_INSTANCE 테이블

BATCH_JOB_EXECUTION_PARAM 테이블

profile
백엔드

0개의 댓글