스프링 배치 공식 레퍼런스를 한글로 번역한 문서입니다.
전체 목차는 여기에 있습니다.
목차
- 8.1. RepeatTemplate
- 8.2. Completion Policies
- 8.3. Exception Handling
- 8.4. Listeners
- 8.5. Parallel Processing
- 8.6. Declarative Iteration
8.1. RepeatTemplate
배치 처리는 간단한 최적화에서든 job 일부로써든, 반복적인 처리를 수행한다.
반복처리를 전략화하고 일반화하기 위해,
스프링 배치는 프레임워크에 얼마나 반복해야 하는지 알려줄 수 있는
RepeatOperations
인터페이스를 제공한다.
RepeatOperations
인터페이스 정의는 다음과 같다:
public interface RepeatOperations {
RepeatStatus iterate(RepeatCallback callback) throws RepeatException;
}
callback은 반복할 비지니스 로직을 넣을 수 있는 인터페이스로, 인터페이스 정의는 다음과 같다:
public interface RepeatCallback {
RepeatStatus doInIteration(RepeatContext context) throws Exception;
}
구현체가 반복을 종료할 때까지 콜백을 반복해서 호출한다.
이 인터페이스는 RepeatStatus.CONTINUABLE
과
RepeatStatus.FINISHED
를 포함하는 열거형(enumeration)을 리턴한다.
RepeatStatus
는 더 할 일이 남아 있는지에 관한 정보를 준다.
일반적으로 RepeatOperations
구현체는 RepeatStatus
를 검사해서
반복을 종료할지 결정한다.
호출자에게 더 이상 처리할 작업이 없다는 신호를 주려면 콜백에서
RepeatStatus.FINISHED
를 리턴하면 된다.
아래 예제에 있는 RepeatTemplate
은 RepeatOperations
의 가장 간단한 구현체다:
RepeatTemplate template = new RepeatTemplate();
template.setCompletionPolicy(new SimpleCompletionPolicy(2));
template.iterate(new RepeatCallback() {
public RepeatStatus doInIteration(RepeatContext context) {
// Do stuff in batch...
return RepeatStatus.CONTINUABLE;
}
});
위 예제에서는 아직 처리할 작업이 남았다는 뜻으로 RepeatStatus.CONTINUABLE
을 리턴한다.
호출자에게 더 이상 처리할 게 없다고 알려주고 싶으면 콜백에서
RepeatStatus.FINISHED
를 리턴하면 된다.
콜백에서 수행하는 작업을 고려해서 반복을 종료하는 경우도 있다.
그렇지 않다면 위 예제에서처럼 콜백과 외부 policy에 결정을 위임하는 한
사실상 무한 루프나 다름없다.
8.1.1. RepeatContext
RepeatCallback
메소드는 RepeatContext
를 파라미터로 받는다.
컨텍스트를 무시하는 콜백도 많지만,
원한다면 실행을 반복하는 동안 데이터를 일시적으로 저장할 수 있다.
iterate
메소드가 종료되면 컨텍스트에 담긴 데이터는 사라진다.
반복 호출을 중첩해서 사용한다면 RepeatContext
는 부모 컨텍스트를 가진다.
iterate
를 호출하는 동안 공유할 데이터를 부모 컨텍스트에 저장하는 경우도 있다.
예를 들어 반복 처리하는 동안 이벤트 발생 횟수를 세고 싶다면
다음 호출로 넘어가도 이 값을 가지고 있어야 한다.
8.1.2. RepeatStatus
RepeatStatus
는 스프링 배치가 처리가 끝났는지 판별하기 위한 열거형(enumeration)이다.
가능한 RepeatStatus
값은 아래 표에 보이는 두 가지가 있다:
Table 18. RepeatStatus Properties
Value | Description |
---|---|
CONTINUABLE | 처리할 작업이 남아 있다. |
FINISHED | 더 이상 반복할 필요가 없다. |
RepeatStatus
값은 안에 있는 and()
메소드를 사용해
논리적인 AND 연산으로 조합할 수 있다.
이를 통해 연속적인 플래그에 AND 연산을 적용할 수 있다.
즉, 둘 중 하나가 FINISHED
라면 결과도 FINISHED
다.
8.2. Completion Policies
RepeatTemplate
의 iterate
메소드 안에서 반복을 중단할지는
RepeatContext
의 팩토리이기도한 CompletionPolicy
가 결정한다.
RepeatTemplate
의 책임은 현재 policy로 RepeatContext
를 생성해
매번 반복할 때마다 RepeatCallback
에 전달하는 것이다.
콜백이 doInIteration
메소드를 완료하면
RepeatTemplate
은 CompletionPolicy
를 호출해
상태(RepeatContext
에 저장돼 있는)를 업데이트하라고 요청해야 한다.
그다음 policy에게 반복을 종료할지 물어본다.
스프링 배치는 간단한 CompletionPolicy
구현체를 제공한다.
SimpleCompletionPolicy
는 고정된 횟수만큼만 반복하게 만든다
(RepeatStatus.FINISHED
를 사용하면 언제든지 조기 종료할 수 있다).
좀 더 세분화해서 결정하려면 자체 completion policy를 구현해야 한다. 예를 들어 커스텀 custom policy로 온라인 시스템이 정상화되면 배치 job을 실행하지 않게 만들 수 있다.
8.3. Exception Handling
RepeatCallback
안에서 예외가 발생하면
RepeatTemplate
은 ExceptionHandler
를 참고해서
예외를 다시 던질지 말지 결정한다.
ExceptionHandler
인터페이스 정의는 다음과 같다:
public interface ExceptionHandler {
void handleException(RepeatContext context, Throwable throwable)
throws Throwable;
}
보통은 주어진 타입의 exception 발행 횟수를 계산해서
limit에 도달할 때 실패하는 식으로 사용한다.
스프링 배치는 SimpleLimitExceptionHandler
와 좀 더 유연한
RethrowOnThresholdExceptionHandler
를 제공한다.
SimpleLimitExceptionHandler
는 limit, exception 타입 프로퍼티가 있어서
exception이 발생할 때마다 타입을 비교한다.
주어진 exception 타입의 모든 하위 클래스도 함께 카운팅한다.
주어진 모든 exception 타입은 계속 무시하다가 limit에 도달하면 예외를 다시 던진다.
다른 exception 타입은 전부 다시 던진다.
SimpleLimitExceptionHandler
에서 선택적으로 사용할 수 있는 중요한 프로퍼티가 있는데,
boolean 타입의 useParent
다.
디폴트는 false
이므로 limit은 현재 RepeatContext
안에서만 사용된다.
true
로 설정하면 중첩된 반복 처리(step 안에 있는 청크 셋같이)
안에 있는 형제 컨텍스트와 limit을 공유한다.
8.4. Listeners
가끔은 반복 처리할 때마다
횡단 관심사(cross cutting concerns)에서도 추가로 콜백을 받고 싶을 수 있다.
스프링 배치는 이를 위한 RepeatListener
인터페이스를 지원한다.
RepeatTemplate
에 RepeatListener
를 등록하면
매번 RepeatContext
, RepeatStatus
와 함께 콜백 받을 수 있다.
RepeatListener
인터페이스 정의는 다음과 같다:
public interface RepeatListener {
void before(RepeatContext context);
void after(RepeatContext context, RepeatStatus result);
void open(RepeatContext context);
void onError(RepeatContext context, Throwable e);
void close(RepeatContext context);
}
모든 반복 전후에 open
, close
로 콜백 받는다.
before
, after
, onError
는 RepeatCallback
을 사용 할 때마다 호출한다.
리스너가 둘 이상이라면 리스트 안에 저장하므로 순서가 정해져 있다.
이때는 open
, before
메소드는 동일한 순서로 호출하는 반면
after
, onError
, close
는 역순으로 호출한다.
8.5. Parallel Processing
RepeatOperations
구현체가 항상 콜백을 순차적으로 실행해야 한다는 법은 없다.
콜백을 병렬 실행하는 구현체도 있다.
스프링은 이를 위해 스프링의 TaskExecutor
전략을 사용해 RepeatCallback
을 실행하는
TaskExecutorRepeatTemplate
을 제공한다.
디폴트는 SynchronousTaskExecutor
를 사용하도록 되어 있어서,
동일한 쓰레드로 전체 반복 처리를 실행하면(일반 RepeatTemplate
처럼) 문제가 생길 수 있다.
8.6. Declarative Iteration
때로는 매번 반복해야 하는 비지니스 로직도 있다.
메세지 파이프라인 최적화가 가장 대표적인 예시다.
메세지가 반복적으로 도착한다면, 메세지 마다 별도로 트랜잭션 비용을 감수하기보다
배치로 처리하는 게 더 효율적이다.
스프링 배치는 이럴 때 사용할,
RepeatOperations
의 메소드 호출을 감싸고 있는 AOP 인터셉터를 지원한다.
RepeatOperationsInterceptor
는 메소드 호출을 가로채서
RepeatTemplate
에 제공한 CompletionPolicy
에 따라 반복 처리한다.
아래 예제는 자바 기반 설정을 사용해서
processMessage
메소드로 서비스를 호출을 반복하게 설정했다
(AOP 인터페이스를 설정에 대한 자세한 정보는 Spring User Guide를 참고하라):
@Bean
public MyService myService() {
ProxyFactory factory = new ProxyFactory(RepeatOperations.class.getClassLoader());
factory.setInterfaces(MyService.class);
factory.setTarget(new MyService());
MyService service = (MyService) factory.getProxy();
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
pointcut.setPatterns(".*processMessage.*");
RepeatOperationsInterceptor interceptor = new RepeatOperationsInterceptor();
((Advised) service).addAdvisor(new DefaultPointcutAdvisor(pointcut, interceptor));
return service;
}
위에 있는 인터셉터는 내부에서 디폴트 RepeatTemplate
을 사용한다.
policy, listener나 다른 것들을
바꾸고 싶으면 RepeatTemplate
인스턴스를 인터셉터에 주입하면 된다.
가로챈 메소드가 void
를 반환하면 인터셉터는 항상 RepeatStatus.CONTINUABLE
을 리턴한다
(이런 경우 CompletionPolicy
가 종료 시점을 알려주지 않으면 무한 루프에 빠질 위험이 있다).
그 외에는 가로챈 메소드가 null
을 반환할 때까지 RepeatStatus.CONTINUABLE
를 리턴한다.
null
을 반환하면 RepeatStatus.FINISHED
를 리턴한다.
결과적으로 타겟 메소드 안에 있는 비지니스 로직이 null
을 리턴하거나,
주입받은 RepeatTemplate
의 ExceptionHandler
가 다시 던진 exception을 던져서
더 이상 할 일이 없음을 알릴 수 있다.
Next :Retry
스프링 배치 재시도(retry) 한글 번역
전체 목차는 여기에 있습니다.