본문 바로가기
Spring/Batch

[Spring] Spring Batch Job 등록부터 실행까지(1)

by 기몬식 2024. 1. 22.

들어가기 전

이전 글 에서 Spring Batch 실행을 위한 프로젝트 환경 구성 및 예제 Job 을 작성 후 실행해 봤습니다. 그렇다면 Spring Batch 는 Job 을 어떤 식으로 생성하고 실행시키는지에 대해 이번 글을 통해서 알아 보도록 하겠습니다.

Step

다음과 같이 Tasklet 으로 구성된 Step 을 Bean 으로 등록합니다.


@Bean
public Step step(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return new StepBuilder("step1", jobRepository)
          .tasklet(tasklet(), transactionManager)
          .build();
}

먼저 StepBuilder 란 JobRepository 및 Listener 와 같은 공통 속성에 대한 액세스를 제공하는 유틸리티 클래스로 StepBuilder 에서 제공하는 메소드에 따라 적절한 하위 빌더 클래스가 생성됩니다.


위의 예제 코드에서는 사용자 정의 Tasklet 기반으로 하는 Step 단계를 생성하기 위한 TaskletStepBuilder 가 생성됩니다. TaskletStepBuilder 의 상속 구조도는 다음과 같습니다.

기본적으로 모든 빌더는 StepBuilderHelper 을 상속 받고 있으며 해당 클래스는 Step 을 생성하는데 공통적으로 필요한 기능을 제공합니다.
다음은 StepBuilderHelper 가 제공하는 주요 메소드입니다.


 

StepBuilderHelper 클래스는 Micrometer 와 관련된 ObservationConvention 을 구성하는 기능을 제공하는데 이 부분은 제가 완전히 무지한 상태라 넘어가도록 하겠습니다. 😓
Micrometer 는 Spring Application 에서 메트릭을 남기기 위한 facade 로 Spring Batch 는 ObservationConvention 의 구현체로 BatchStepObservationConvention 을 통해 StepContext 상태를 추적하는 기능을 제공하는 것 같습니다. 이 부분은 추후에 학습한 후 작성하도록 하겠습니다. 자세한 내용은 해당 페이지를 참고 부탁 드립니다.

 


  • startLimit: CommonStepProperties 의 startLimit property 에 값을 저장합니다. 해당 설정 값만큼 Step 이 실행 가능함을 의미합니다.
  • listener(object): BeforeStep, AfterStep 어노테이션이 명시된 메소드가 존재하는 리스너를 StepListenerFactoryBean 에 등록합니다.
  • listener(StepExecutionListener): Step 의 라이프사이클을 관리하는 StepExecutionListener 를 등록합니다. beforeStep, afterStep 관련한 메소드를 정의할 수 있습니다.
  • allowStartIfComplete: 해당 메소드에 인자를 true 로 설정하면 JobInstance 해당 Step 도 포함하여 재실행합니다.
  • enhance: 인자로 AbstractStep 을 받습니다. 현재 StepBuilderHelper 에서 관리 중인 모든 properties 를 인자로 넘어온 Step 에 넘겨줍니다.

 

TaskLetStep 은 성공한 Step의 BatchStatus 를 Completed 로 관리합니다. 때문에 Step 을 재실행 시키면 실패한 Step 만을 재실행시키게 됩니다. 해당 메소드 인자를 true 로 설정하면 Completed 임에도 재 실행 하게 됩니다.

 


위와 같이 StepBuilderHelper 에서 제공하는 메소드를 통해 Step 을 생성하는데 필요한 속성들을 설정합니다. 그 후 AbstractTaskletStepBuilder 은 StepBuilderHelper 가 수집한 구성 요소를 통해 build 메소드를 통해 TaskletStep 을 생성하여 반환합니다.


public TaskletStep build() {
  registerStepListenerAsChunkListener();
  TaskletStep step = new TaskletStep(getName());
  super.enhance(step);
  step.setChunkListeners(chunkListeners.toArray(new ChunkListener[0]));
  if (this.transactionManager != null) {
    step.setTransactionManager(this.transactionManager);
  }

  if (transactionAttribute != null) {
    step.setTransactionAttribute(transactionAttribute);
  }

  if (stepOperations == null) {
    stepOperations = new RepeatTemplate();
    if (taskExecutor != null) {
      TaskExecutorRepeatTemplate repeatTemplate = new TaskExecutorRepeatTemplate();
      repeatTemplate.setTaskExecutor(taskExecutor);
      repeatTemplate.setThrottleLimit(throttleLimit);
      stepOperations = repeatTemplate;
    }
    ((RepeatTemplate) stepOperations).setExceptionHandler(exceptionHandler);

  }
  step.setStepOperations(stepOperations);
  step.setTasklet(createTasklet());
  step.setStreams(streams.toArray(new ItemStream[0]));

  try {
    step.afterPropertiesSet();
  }
  catch (Exception e) {
    throw new StepBuilderException(e);
  }
  return step;
}

TaskletStep 을 생성한 객체를 enhance()의 인자로 넘긴 후 이를 위임한 다음 서브 클래스에서 createTasklet()을 위임하여 실제 Tasklet 을 생성합니다. 이렇게 생성된 Step 은 Bean 으로 등록되어 스프링 컨테이너에 저장되게 됩니다.

Job

다음과 같이 Step 을 가지는 Job 을 Bean 으로 등록합니다.


@Bean
public Job myJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return new JobBuilder("myJob", jobRepository)
          .start(step(jobRepository, transactionManager))
          .build();
}

먼저 JobBuilder 란 JobRepository 와 같은 공통 속성에 대한 액세스를 제공하는 유틸리티 클래스로 JobBuilder 에서 제공하는 메소드에 따라 적절한 하위 빌더 클래스가 생성됩니다.


위 예제 코드에서는 Step 을 인자로 받는 start() 메소드를 사용하는데 JobBuilder 는 내부적으로 SimpleJobBuilder 를 생성하여 SimpleJob 을 생성합니다. 반대로 Flow 를 인자로 받는 start() 또는 Step 을 인자로 받는 flow() 메소드를 사용하게 되면 JobBuilder 는 내부적으로 FlowJobBuilder 를 생성하여 FlowJob 을 생성하게 됩니다. SimpleJobBuilder 의 기본 상속 구조도는 다음과 같습니다.

기본적으로 모든 빌더는 JobBuilderHelper 을 상속 받고 있으며 해당 클래스는 Job 을 생성하는데 공통적으로 필요한 기능을 제공합니다. 다음은 JobBuilderHelper 가 제공하는 주요 메소드입니다.


 

JobBuilderHelper 클래스 또한 StepBuilderHelper 와 같이 Micrometer 와 관련된 ObservationConvention 을 구성하는 기능을 제공하는데 이 부분은 제가 완전히 무지한 상태라 넘어가도록 하겠습니다. 😓

 


  • validator: job parameters 의 유효성을 검사하는데 사용할 인터페이스를 등록합니다. DefaultJobParametersValidator 을 기본 구현체로 제공합니다.
  • incrementer: job parameters 의 시퀀스와 같이 필요한 값을 증가시켜 다음에 사용될 job parameters 객체를 반환합니다. RunIdIncrementer 을 기본 구현체로 제공합니다.
  • listener(object): BeforeJob, AfterJob 어노테이션이 명시된 메소드가 존재하는 리스너를 JobListenerFactoryBean 에 등록합니다.
  • listener(JobExecutionListener): Job 의 라이프사이클을 관리하는 JobExecutionListener 를 등록합니다. beforeJob, afterJob 관련한 메소드를 정의할 수 있습니다.
  • preventRestart: Job 이 실패한 경우에 다시 시작하지 못하도록 플래그를 설정합니다. AbstractJob 클래스에 있는 restartable 맴버 편수를 false 로 설정합니다.
  • enhance: 인자로 AbstractJob 을 받습니다. 현재 JobBuilderHelper 에서 관리 중인 모든 properties 를 인자로 넘어온 Job 에 넘겨줍니다.

위와 같이 JobBuilderHelper 에서 제공하는 메소드를 통해 Job 을 생성하는데 필요한 속성들을 설정합니다. 그 후 AbstractTaskletJobBuilder 은 JobBuilderHelper 가 수집한 구성 요소를 통해 build 메소드를 통해 Job 을 생성하여 반환합니다.


public Job build() {
  if (builder != null) {
    return builder.end().build();
  }
  SimpleJob job = new SimpleJob(getName());
  super.enhance(job);
  job.setSteps(steps);
  try {
    job.afterPropertiesSet();
  }
  catch (Exception e) {
    throw new JobBuilderException(e);
  }
  return job;
}

SimpleJob 을 생성한 객체를 enhance()의 인자로 넘긴 후 이를 위임한 다음 Job 가지고 있는 Step 목록을 셋팅합니다. 이렇게 생성된 Job 은 Bean 으로 등록되어 스프링 컨테이너에 저장되게 됩니다.

위와 같이 Job 과 Step 은 Builder Pattern 을 이용하여 유사한 방법으로 생성이 되어집니다. 하지만 Job 은 단순한 일련의 연속인 Step 과는 다르게 더 나아가 여러 워크플로우와 재시도 및 복구, 병렬 처리와 같은 추가 기능을 제공합니다. 위와 같은 기능을 제공하는 Job 을 생성해주는 빌더들에 대해 알아보겠습니다.

SimpleJobBuilder

작성 예정

FlowJobBuilder

작성 예정

실행

출처

작성 예정


오탈자 및 오류 내용을 댓글 또는 메일로 알려주시면, 검토 후 조치하겠습니다.

'Spring > Batch' 카테고리의 다른 글

[Spring] Spring Batch 시작하기 01  (1) 2024.01.14
[Spring] Spring Batch란?  (2) 2023.12.18