ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 배치가 뭐길래 : Spring Batch 5
    카테고리 없음 2025. 5. 3. 13:21

    배치

    Spring Batch는 스케쥴러를 지원하지 않음 (공식 웹사이트 첨부 필요)

    Spring Batch의 목적은 대용량 처리

     

    스케쥴러 : 일정 주기로 실행하는 것

    Quatz는 뭔지?

     

    Job(배치 할 것)은 여러개의 Step으로 구성됨

    Step은 ItemReader, ItemProcesor, ItemWriter로 구성됨

     

    Job을 실현하기 위해 JobLauncher가 필요

     

    모두 JobRepository 통해서 데이터랑 통신하는듯?

     

    Job : Job 이름 정의 가능, Step 정의와 순서, Job 재사용 가능성 정의

    JobInstance :논리적으로 Job을 실행, (어제 실행한 Job인지, 오늘 실행한 Job인지.. JobParameters를 이용해서 구분)

    JobExecution : Job을 실행하는 단일 시도. 실패했던 JobInstance에 대한 새로운 실행을 하면 새로운 JobExecution이 생성

    - BatchStatus : 실행 상태 (실행중이면 started, 실패하면 failed, 성공하면 completed)

    - ExitStatus : 실행 결과. ExitCode 등을 포함

     

    Step : Job은 하나 이상의 Step으로 구성됨

    배치 작업의 독립적이고 순차적인 단계를 캡슐화하는 도메인 객체

    모든 Job은 이상의 Step으로 이뤄짐

    Step의 내용은 개발자의 재량

     

    StepExecution

    - Status 실행 상태

    - ExitStatus 실행의 결과

    Read Count, WriteCounte, CommitCount, RollbackCount, FilterCount등의 정보를 담고 있음

     

    JobRepository : Job, Step 구현을 위한 CRUD 작업을 제공

     

    JobLancher : Jobt을 시작하기 위한 간단한 인터페이스

     

    메타데이터를 그대로 사용할 수 있음. 비즈니스 로직에 집중하게 해줌

     

     

    아이템 : 작업에 사용하는 데이터 (예를 들면 DB의 한 row)

     

    ItemReader : Step에서 한 항목씩 검색한다. 모든 항목이 소진된 경우 null을 반환한다. (db 조회)

     

    ItemWriter : 여러 출력 항목을 나타냄 (db에 저장 등) (마지막에)

     

    ItemProcessor : 비즈니스 처리르 담당. 항목이 유효하지 않으면 null을 반환

     

    프레임워크 사용하므로 JobLauncer나 JobRepo는 구현 안해도 됨

     

    Tasklet

    - 익명 Tasklet

    - chunk 

    chunk : 각 커밋 사이에 처리되 row의 수

    성공 시 cunk 만큼 커밋, 실패 시 chunk 만큼 롤백

     

    write에서는 chunk를 한버에 write

     

    ItemReader

    - cursor, paging

    cursor : 1 connection에 1 item 가져옴

    paging : 1 connection에 N개의 Item 가져옴

     

    page size는 chunk size와 동일하게 설정하는 것이 좋음

    page size > chunk size면 하나의 트랜잭션 처리를 위해 paging을 여러번 해야됨

     

    ItemProcessor (Optional)

    비즈니스 코드를 담는 곳

    데이터 실패 시 null을 반환 (?)

     

    실패 여부에 따라 조건문으로 step을 실행할 수 있음

     

    테스트 코드 작성이 필요. QA 하기 어려움. 통합테스트도 필요, 각각의 단위 테스트도 필요

     

    관리 도구

    : Cron (리눅스 작업 스케쥴러)

    : Quartz + Admin (스케쥴러 프레임워크 + 관리자 페이지 구현)

    : CI Tool (ex. Jenkins)

     

    젠킨스 장점 : 실행 이력 / 로그 관리에도 좋음

     

    ✅ Spring Batch ItemReader에서 로그가 안 찍히는 이유 정리

    🔹 문제 상황

    ItemReader 설정 코드에 아래처럼 로그를 찍었지만, 로그가 한 번만 출력되고 이후에는 보이지 않음:

    java
    복사편집
    @Bean public ItemReader<Long> setSubscriptionEndDtItemReader() { log.debug("setSubscriptionEndDtItemReader execute."); // ← 로그 여기 return new JpaCursorItemReaderBuilder<Long>() .name("setSubscriptionEndDtItemReader") .queryString(...) .entityManagerFactory(emf) .build(); }

    🔹 원인

    • 이 로그는 ItemReader 빈 생성 시점에만 실행됨.
    • 실제로 read() 메서드가 실행될 때 찍히는 로그가 아님.
    • 따라서 Step 실행 중에 Reader가 동작하는지 확인할 수 없음.

    ✅ 왜 그런가?

    구분설명
    @Bean 메서드 Spring이 어플리케이션 시작 시 한 번만 실행해서 빈을 생성함
    log.debug(...) 위 메서드 안에 있으면 빈 생성 시점에만 실행됨
    read() 메서드 Step 실행 중에 호출되지만, JpaCursorItemReader 내부이므로 우리가 로그를 못 넣음

    ✅ 해결 방법

    1. read() 호출 시점에 로그를 보고 싶다면

    JpaCursorItemReader를 감싸는 커스텀 ItemReader를 만들어서 read()를 직접 override해야 함:

    java
    복사편집
    @Bean public ItemReader<Long> setSubscriptionEndDtItemReader() { JpaCursorItemReader<Long> delegate = new JpaCursorItemReaderBuilder<Long>() .name("setSubscriptionEndDtItemReader") .entityManagerFactory(emf) .queryString(query) .build(); return new ItemReader<Long>() { @Override public Long read() throws Exception { Long id = delegate.read(); log.debug(">>> read() called. id: {}", id); return id; } }; }

    ✅ 핵심 요약

    질문정리
    로그가 왜 안 찍혀? @Bean 메서드 안에서만 찍으면, 빈 생성 시점에만 로그가 출력
    실제 Step에서 Reader가 호출될 때 로그 찍으려면? read() 메서드를 오버라이드해서 직접 로그 넣어야 함
    JpaCursorItemReader는 왜 로그 못 넣어? 내부 구현에 접근할 수 없고, 우리가 read()를 override하지 않았기 때문

     

     

     

     

     

     

     

    레퍼런스

    https://www.youtube.com/watch?v=1xJU8HfBREY

     

Designed by Tistory.