Spring Batch 조건별 Step 분기 처리 완벽 가이드 (Flow, Decider)

안녕하세요.

배치 작업을 수행하다 보면 항상 일직선으로만 일이 진행되지는 않습니다. “데이터가 있으면 A로 가고, 없으면 종료해라” 혹은 “Step 1이 실패하면 복구 Step을 실행하고, 성공하면 바로 다음으로 가라”와 같은 조건부 로직이 필요합니다.

오늘은 Spring Batch의 강력한 흐름 제어 기능인 분기 처리(Branching) 방법을 기초부터 심화까지 정리해 드립니다.


1. ExitStatus를 이용한 단순 분기 (on().to())

가장 직관적인 방법입니다. 앞선 Step의 종료 코드(ExitStatus)를 확인하여 다음에 실행할 Step을 결정합니다.

Spring Batch 조건별 Step 분기 처리 완벽 가이드 (Flow, Decider) 이미지 1

코드 예제 1: 성공/실패에 따른 분기

@Bean
public Job conditionalJob() {
    return new JobBuilder("conditionalJob", jobRepository)
            .start(step1())
                .on("FAILED") // 실패했을 때
                .to(failureHandlingStep()) // 실패 처리 Step으로 이동
                .on("*") // 실패 처리 후에는
                .end() // 종료
            .from(step1())
                .on("COMPLETED") // 성공했을 때
                .to(step2()) // 다음 단계로 진행
                .next(step3())
                .on("*")
                .end()
            .end()
            .build();
}
  • on("FAILED"): 특정 ExitStatus를 매칭합니다. 와일드카드(*) 사용이 가능합니다.
  • to(): 이동할 대상 Step을 지정합니다.
  • from(): 다시 특정 Step의 결과로부터 분기 로직을 시작할 때 사용합니다.

2. 복잡한 로직을 위한 JobExecutionDecider

on().to() 방식은 편리하지만, 비즈니스 로직이 복잡해지면(예: DB를 조회해본 결과에 따라 분기) Job 설정 코드가 지저분해집니다. 이때 사용하는 것이 바로 Decider입니다.

2.1 Decider 구현

public class OddEvenDecider implements JobExecutionDecider {
    @Override
    public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
        Random random = new Random();
        int randomNumber = random.nextInt(10);

        if (randomNumber % 2 == 0) {
            return new FlowExecutionStatus("EVEN");
        } else {
            return new FlowExecutionStatus("ODD");
        }
    }
}

2.2 Job 설정에 적용

Spring Batch 조건별 Step 분기 처리 완벽 가이드 (Flow, Decider) 이미지 2
@Bean
public Job deciderJob() {
    return new JobBuilder("deciderJob", jobRepository)
            .start(step1())
            .next(oddEvenDecider()) // 디사이더 실행
            .from(oddEvenDecider())
                .on("EVEN").to(evenStep())
            .from(oddEvenDecider())
                .on("ODD").to(oddStep())
            .end()
            .build();
}

@Bean
public JobExecutionDecider oddEvenDecider() {
    return new OddEvenDecider();
}

Decider의 장점:
* 분기 로직과 Step 구성 로직이 분리되어 코드가 깨끗해집니다.
* StepExecution뿐만 아니라 JobExecution 전체를 참조할 수 있어 풍부한 데이터를 바탕으로 의사결정을 내릴 수 있습니다.


3. ExitStatus vs BatchStatus 주의점

분기 처리 시 가장 많이 하는 실수가 두 상태를 혼동하는 것입니다.

  • BatchStatus: Job이나 Step의 최종 실행 결과 (COMPLETED, FAILED, STOPPED 등). DB에 저장되는 공식 상태입니다.
  • ExitStatus: Step이 끝났을 때의 ‘종료 코드’. 분기 처리는 이 ExitStatus를 기준으로 합니다. 기본적으로 BatchStatus와 동일하게 설정되지만, 개발자가 원한다면 on("CUSTOM_STATUS")처럼 임의로 커스텀할 수 있습니다.

4. 결론

Spring Batch의 분기 처리는 단순한 에러 처리를 넘어, 지능적인 배치 워크플로우를 가능하게 합니다.

  1. 간단한 성공/실패 분기는 on().to()
  2. 데이터나 복잡한 조건에 따른 분기는 JobExecutionDecider

이 두 가지 도구를 마스터하면, 어떤 복잡한 요구사항도 대응할 수 있는 유연한 배치 시스템을 구축할 수 있습니다. 오늘 내용이 여러분의 배치 설계에 큰 도움이 되길 바랍니다.

관련 글 보기