Spring Batch - 4.x버전으로 다시 시작 - 1

Kim Dong Kyun·2023년 6월 9일
1
post-thumbnail
post-custom-banner

개요

너무 안타깝지만, Spring Batch 5.0 버전은 스프링 배치 자체에 익숙해지고 나서 시작하려고 한다. 버전 마이그레이션에 집중하는 것보다는 현재는 스프링 배치 자체에 집중해야 할듯. 4버전으로 실습 한 후에, 마이그레이션 시리즈를 이어가려고 한다.

기억보단 기록을

위 블로그에서 나온 내용들을 쭉 실습 할 생각이고, 추가적인 내용이 있으면 (추가하고 싶은 내용이 있다면) 더 적을 예정.


시작

우선, 새 프로젝트를 부트해주고 의존성을 추가한다

  • 버전은 JDK 17, SpringBoot 2.7.12 를 선택했다 (선택 가능한 가장 옛 버전이라)
  • 의존성은 주석으로 표시했다.

제일 먼저 할 일은, 우리가 만든 프로젝트 어플리케이션에 Spring Batch 기본 설정 적용하는 것.

위와 같이 설정해주고, 시작해보자


로컬에서 간단한 Job, Step 만들어보기

@Slf4j // log 사용을 위한 lombok 어노테이션
@RequiredArgsConstructor // 생성자 DI를 위한 lombok 어노테이션
@Configuration
public class SimpleJobConfiguration {
    private final JobBuilderFactory jobBuilderFactory; // 생성자 DI 받음
    private final StepBuilderFactory stepBuilderFactory; // 생성자 DI 받음

    @Bean
    public Job simpleJob() {
        return jobBuilderFactory.get("simpleJob")
                .start(simpleStep1())
                .build();
    }

    @Bean
    public Step simpleStep1() {
        return stepBuilderFactory.get("simpleStep1")
                .tasklet((contribution, chunkContext) -> {
                    log.info(">>>>> This is Step1");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }
}
  • 위와 같이 설정 후 로컬에서 돌리면, 잘 작동하는 모습을 볼 수 있다.
  • 그리고, 이전에 했던 마리아DB 연동 작업도 다시 해보자

멀티 프로필 작성 후 마리아디비 연동


spring:
  profiles:
    active: mariadb

---

spring:
  profiles:
    active: local
  datasource:
    hikari:
      jdbc-url: jdbc:h2:mem:db;MODE=MYSQL;
      username: sa
      password:
      driver-class-name: org.h2.Driver
  batch:
    job:
      enabled: true

---

spring:
  profiles:
    active: mariadb
  datasource:
    hikari:
      jdbc-url: jdbc:mariadb://localhost:3306/commerce
      // 본인에 맞는 url
      username: 유저네임
      password: 비밀번호
      driver-class-name: org.mariadb.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
        show_sql: true
        format_sql: true
  batch:
    job:
      enabled: true
    jdbc:
      initialize-schema: always

yml 파일을 다음과 같이 작성한다.

  • 유저네임, url, 비밀번호는 각자 설정에 맞게!
 batch:
    job:
      enabled: true
    jdbc:
      initialize-schema: always
  • 위와 같이 야믈에서 initialize-schema 를 always로 바꾸면 자동으로 스키마가 설정된다
  • 아니면, DB 콘솔에서 추가도 가능하다 ( 이 방법은 전 포스트(링크)에 적어놓음)

마지막으로, 혹시 문제가 있는 경우 (BAD SQL EXCEPTION 등)

  • 스키마 드랍하고 다시 실행하면 된다.
  • 나의 경우 5버전 스키마와 4버전 스키마가 충돌해서, 5버전 스키마를 드랍하고 다시 설정했다.

생성된 스키마 둘러보기

BATCH_JOB_PARAMETER

@Slf4j // log 사용을 위한 lombok 어노테이션
@RequiredArgsConstructor // 생성자 DI를 위한 lombok 어노테이션
@Configuration
public class SimpleJobConfiguration {
    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job simpleJob() {
        return jobBuilderFactory.get("simpleJob")
                .start(simpleStep1(null))
                .build();
    }

    @Bean
    @JobScope
    public Step simpleStep1(@Value("#{jobParameters[requestDate]}") String requestDate) {
        return stepBuilderFactory.get("simpleStep1")
                .tasklet((contribution, chunkContext) -> {
                    log.info(">>>>> This is Step1");
                    log.info(">>>>> requestDate = {}", requestDate);
                    return RepeatStatus.FINISHED;
                })
                .build();
    }
}

위에서 작성한 실습 코드를 실행 해봤다면, 위와 같이 코드를 바꿔준다.

  • @JobScope 어노테이션 붙여야함!
  • 더불어서, @Value 어노테이션을 자동 import 하게 되면 lombok의 어노테이션을 임포트하는데, 이거 말고
import org.springframework.beans.factory.annotation.Value;
  • 이걸 임포트 해야한다(그래야 다음 작업을 통해 밸류 주입이 가능하다)

  • 프로젝트 run 옆 설정에서, Edit Configurations

  • Program Arguments 추가하고, 원하는 값 내 경우 (requestDate=20180805) 로 설정(선생님 블로그와 같다)

이후에 실행할 경우, 다음 결과를 얻을 것이다

위와 같이 parameters = "우리가 설정한" 패러미터로 설정됨.

그리고 다시 돌려보면? 다음 에러를 만나게 된다.

Caused by: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={requestDate=20180805}.  If you want to run this job again, change the parameters.

job instance가 이미 같은 패러미터로 존재한다!
-> 즉, JOB Parameter 당 한번의 실행이 보장된다 == 패러미터당 하나의 인스턴스 생성이 보장된다

  • 그리고 그 인스턴스들은 BATCH_JOB_INSTANCE 테이블에서 확인 가능하다


BATCH_JOB_EXECUTION

다음으로 살펴 볼 것은 BATCH_JOB_EXECUTION 테이블.

BATCH_JOB_INSTANCE 테이블과 부모자식 관계.

JOB EXECUTION 테이블은 자신의 부모인 JOB INSTANCE가 실행/실패했던 모든 내역을 가진다.

위와 같이 시도한 두 개의 패러미터의 EXECUTION이 COMPLETE로 잘 저장되어 있는 모습.

  • 그렇다면 실패 내역도 저장해볼까?
@Slf4j // log 사용을 위한 lombok 어노테이션
@RequiredArgsConstructor // 생성자 DI를 위한 lombok 어노테이션
@Configuration
public class SimpleJobConfiguration {
    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job simpleJob() {
        return jobBuilderFactory.get("simpleJob")
                .start(simpleStep1(null))
                .next(simpleStep2(null))
                .build();
    }

    @Bean
    @JobScope
    public Step simpleStep1(@Value("#{jobParameters[requestDate]}") String requestDate) {
        return stepBuilderFactory.get("simpleStep1")
                .tasklet((contribution, chunkContext) -> {
                    throw new IllegalArgumentException("step1에서 실패합니다.");
                })
                .build();
    }

    @Bean
    @JobScope
    public Step simpleStep2(@Value("#{jobParameters[requestDate]}") String requestDate) {
        return stepBuilderFactory.get("simpleStep2")
                .tasklet((contribution, chunkContext) -> {
                    log.info(">>>>> This is Step2");
                    log.info(">>>>> requestDate = {}", requestDate);
                    return RepeatStatus.FINISHED;
                })
                .build();
    }
}
  • 위에서 tasklet을 throw new EXCEPTION으로 수정한 모습
  • 실행해보자!

다음과 같이 FAILED 상태와 함께 EXIT 메시지까지 매우 자세하게 나오는 모습.

여러번 시도해서 실패해도, EXECUTION은 위와 같이 쌓이고

해당 패러미터의 INSTANCE는 동일하다.

그렇다면 성공시켜볼까? 코드를 바꿔주자


// 이전코드
  @Bean
    @JobScope
    public Step simpleStep1(@Value("#{jobParameters[requestDate]}") String requestDate) {
        return stepBuilderFactory.get("simpleStep1")
                .tasklet((contribution, chunkContext) -> {
                    throw new IllegalArgumentException("step1에서 실패합니다.");
                })
                .build();
    }

// 이후코드

   @Bean
    @JobScope
    public Step simpleStep1(@Value("#{jobParameters[requestDate]}") String requestDate) {
        return stepBuilderFactory.get("simpleStep1")
                .tasklet((contribution, chunkContext) -> {
                    log.info(">>>>> This is Step2");
                    log.info(">>>>> requestDate = {}", requestDate);
                    return RepeatStatus.FINISHED;
                })
                .build();
    }
  • 아래에 있는 코드로 실행!

BATCH_EXECUTION 테이블을 봄녀

다음과 같이 COMPLETE 됨을 알 수 있다.

여기서 알 수 있는점

BATCH INSTANCE는 "실패"의 경우에는 같은 패러미터로 재시도 가능하다. 즉, 한 패러미터에 대해서 인스턴스가 "성공"하면 그 패러미터로는 중복 시도 불가
-> 여러번 시도해서 성공할 때만 저장 가능! (통계 데이터 등)


BATCH INSTANCE, BATCH EXECUTION 의 관계!
JOB Parameter에 알아본 시간.

post-custom-banner

0개의 댓글