Spring

Spring Boot Batch 적용하기 - 2

댕발바닥 2024. 9. 21. 19:53

1. Step Skip

 

Step 처리 도중에서 설정한 Exception이 발생하게 되면 해당 데이터를 건너뛰는 기능입니다.

데이터의 작은 오류에 대해서 Step 의 실패 처리 대신 Skip 을 함으로써 배치 수행의 빈번한 실패를 줄일 수 있습니다.

Skip 제한을 초과하는 경우가 되면 Exception이 발생됩니다.

spring batch skip

 

ItemReader

item 을 읽던 도중 예외가 발생하게 되면 해당 item 을 skip 하고 다음 item 을 읽습는다.

 

ItemProcessor

item 을 처리하던 도중 예외가 발생하면 해당 Chunk 의 첫 단계로 돌아가서 itemReader로부터 다시 데이터를 전달받습니다.
itemProcessor 는 다시 item 을 받아 실행하는데 이전 실행에서 발생한 예외 정보가 내부적으로 남아있어 위의 그림처럼 item2 의 차례가 온다면 처리하지 않고 넘어갑니다.

 

itemWriter

writer 에서 예외가 발생하게 되면 다시 Chunk 단위로 ItemReader 로 돌아갑니다.

write 작업 실패시 데이터 처리를 위해 재동하게 되며, ItemProcessor 는 ItemWriter 로 리스트가 아니라 한 건씩만 보내서 처리합니다.

 

 

2. Step Retry

Step 처리 도중에서 설정한 Exception이 발생하게 되면 재시도 기능입니다.

Skip 과 다르게 ItemReader 에서는 지원하지 않으며, ItemProcessor, ItemWriter 에서만 Retry 가 가능합니다.

Retry Count 는 Item 마다 각각 존재합니다.

spring batch retry

 

ItemProcessor

예외가 발생한다면 다시 Chunk 처음부터 처리합니다.

 

itemWriter

writer에서 예외가 발생하게 되면 다시 Chunk 단위로 ItemReader 로 돌아가 원래 List로 재시도를 진행합니다.

 

 

 

3.  Skip, Retry 실전 연습

 

아래와 같이 Skip 정책을 설정하였습니다.

@Bean
@JobScope
public Step skipStep(JobRepository jobRepository) {
    return new StepBuilder("skipStep", jobRepository)
            .listener(stepExecutionListener)
            .<BoardTbEntity, BoardTbEntity>chunk(10, transactionManager)
            .reader(skipJpaPagingItemReader())
            .processor(skipProcessor())
            .writer(skipWriter())
            .faultTolerant() //  내결함성 기능 활성화
            .skipLimit(3) //  skip 허용 횟수, 해당 횟수 초과 시 Error 발생, Skip 사용시 필수 선언
            .skip(SQLException.class) //  SQLException 에 대해서는 skip
            .noSkip(NullPointerException.class) //  NullPointerException 에 대해서는 skip 하지 않음
            .build();
}

 

 

강제 Skip 발생을 위하여 Exception을 발생시켰습니다.

@Bean
@StepScope
public ItemProcessor<BoardTbEntity, BoardTbEntity> skipProcessor() {
    return board -> {
        BoardTbEntity newBoard = new BoardTbEntity();
        newBoard.setCommentCount(board.getCommentCount());
        newBoard.setLineType(board.getLineType());
        newBoard.setPostType(board.getPostType());
        newBoard.setWriterType(board.getWriterType());
        newBoard.setStatus(board.getStatus());
        newBoard.setView(board.getView());
        newBoard.setContentEmbedded(board.getContentEmbedded());
        newBoard.setReport(board.getReport());
        newBoard.setRecommendCount(board.getRecommendCount());
        if (board.getContentEmbedded().getIp() != null && board.getContentEmbedded().getIp().startsWith("1.111.111.111")) {
            log.info("강제 SQLException 발생 후 SKIP");
            throw new SQLException();
        }
        return newBoard;
    };
}

 

아래 로그를 보게되면 SKIP이 발생된 이후 정상적으로 처리되는것을 확인할 수 있었다. 또한 배치 스텝 execution 테이블에서 데이터가 1건이 SKIP되고 처리된것을 확인 할 수 있었습니다.

spring bathc skip
batch_step_execution

 

 

 

아래와 같이 Retry 정책을 설정하였습니다.

@Bean
@JobScope
public Step retryStep(JobRepository jobRepository) {
    return new StepBuilder("retryStep", jobRepository)
            .listener(stepExecutionListener)
            .<BoardTbEntity, BoardTbEntity>chunk(10, transactionManager)
            .reader(retryJpaPagingItemReader())
            .processor(retryProcessor())
            .writer(retryWriter())
            .faultTolerant()
            .retry(SQLException.class)
            .retryLimit(3)
            .build();
}

 

 

강제 Retrty 발생을 위하여 Exception을 발생시켰습니다.

@Bean
@StepScope
public ItemProcessor<BoardTbEntity, BoardTbEntity> retryProcessor() {
    return board -> {
        BoardTbEntity newBoard = new BoardTbEntity();
        newBoard.setCommentCount(board.getCommentCount());
        newBoard.setLineType(board.getLineType());
        newBoard.setPostType(board.getPostType());
        newBoard.setWriterType(board.getWriterType());
        newBoard.setStatus(board.getStatus());
        newBoard.setView(board.getView());
        newBoard.setContentEmbedded(board.getContentEmbedded());
        newBoard.setReport(board.getReport());
        newBoard.setRecommendCount(board.getRecommendCount());
        if (board.getContentEmbedded().getIp().startsWith("1.111.111.111")) {
            log.info("강제 SQLException 발생 후 RETRY");
            throw new SQLException();
        }
        return newBoard;
    };
}

 

아래 로그를 보게되면 Retry가 발생되고 제한을 초과하여 Exception이 발생되었습니다.. 또한 배치 스텝 execution 테이블에서 실패건으로 적재된 것을 확인 할 수 있었습니다.

spirnb batch retry

 

batch_step_execution

 

 

 

 

 

https://dev-jwblog.tistory.com/141#article-3--2--step-%EC%97%90%EC%84%9C-skip-%EC%82%AC%EC%9A%A9