https://godekdls.github.io/Spring%20Batch/introduction/#11-background
굉장히 잘 번역되어져 있다.
간단하게 요약하자면, 스프링 배치 프로젝트는 배치를 스프링에 사용할 수 있도록 만든 프레임워크 이다.
프레임워크단에서 프로세싱 작업에 대한 구조를 제공하고 사용자는 비즈니스 로직에 더욱 집중할 수 있다.
재사용도 가능하다. 병렬 프로세싱도 가능하다 등등
나머지는 기본 가이드라인, Batch Processing에서 스프링 배치의 활용이 잘 나와있으니까 읽어보면 된다.
전체 배치 프로세스를 캡슐화한 엔터티
XML 기반, 자바 기반 설정 둘다 지원
스프링 배치에서 Job
은 단순히 Step
인스턴스의 컨테이너 개념이다. 논리적으로 한 플로우에 속한 여러 Step을 결합한다
JOB은 다음과 같은 속성을 정의할 수 있다.
- JOB의 이름
- Step
인스턴스 정의와 순서
- Job의 재시작 가능 여부
SimpleJob
은 스프링 배치에서 디폴트로 제공하는 간단한 Job 인터페이스 구현체로 Job의 일부 표준 기능을 구현한다.
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footboolJob")
.start(playerLoad())
.next(gameLoad())
.next(playerSummarization())
.end()
.build();
}
JobInstance
는 논리적인 Job 실행을 말한다.
"EndOfDay" Job처럼 하루가 끝날 때마다 한번 실행돼야 하는 배치를 생각해보자. 21일 실행, 22일 실행 각각의 실행이 발생할텐데 이 "실행 1번"을 담당하는 객체가 JobInstance
라고 보면된다.
추적이 용이
JobInstance를 배치해둠으로서 각 배치 작업에 대한 추적
이 가능해진다.
즉 21일 실행이 실패 났을경우 21일 EndOfDay의 JobInstance만 확인하면 된다.
Entity
특정 Job내에서 JobInstance는 식별가능한 Entity 도메인이다.
다만 1월 1일이 실패 됐을때 재처리를 위해서 1월1일에 해당하는 JobInstance를 재실행할 수 있는데 실행결과는 여럿 가질 수 있지만, 해당 JobParameter에 상응하는 JobInstance
는 Job내에 유일해야한다.
즉 재처리가 됐다하더라도 1월1일에 실행한 동일한 JobInstance가 실행이 된다는 말.
만약 JobInstance를 새로 만들어야 할 경우는 재실행이 아닌 처음부터 시작
이어햐 한다는 것.
이미 있던 Instance를 쓴다는 것은 실패했던 부분 부터 다시 시작
을 의미
JobInstance
는 다른 JobInstance
들과 어떻게 구분하는가를 이야기 할 떄 JobParameter
를 이야기 할 수 있다.
JobParameter란 배치 Job을 시작할 때 사용하는 파라미터 셋을 가지고 있는 객체.
따라서 Job을 식별하거나 참조 데이터로도 사용할 수 있다.
따라서 다음과 같은 공식으로 이야기 할 수 있을 것 같다.
$$ JobInstance = Job + 식별 JobParameter $$
다만 모든 Job Parameter가 JobInstance를 식별하는데 사용하지 않는다. 기본적으로는 그렇지만 JobInstance Id에 관여하지 않는 파라미터를 사용할 수 도 있음.
JobExecution의 개념은 Job
을 한번 실행하려 했다는 것
하나의 실행은 성공하거나 실패하게 되는데, JobInstance
는 실행이 성공적으로 종료되기전까지는 완료하지 않음
으로 간주한다.
따라서 EndOfDay의 Job이 실행되고 1월 1일 JobInstance가 만들어진 뒤 JobExecution을 통해 작업을 실행하게 된다. 그러나 만약 첫번째 JobExecution이 실패하게 된다면, JobInstance는 새 JobExecution
을 생성하여 작업을 종료하려 할 것이다.
이때 여전히 JobExecution은 1개이다.
위 3개념을 다시 요약해보자면
JobExeuction은 다음과 같은 Properties 를 가지고 있다.
Property | Definition | 기타 |
---|---|---|
Status | 실행상태를 나타내는 BatchStatus 오브젝트. | BatchStatus#STARTED : 실행중 BatchStatus#FAILED : 실패 BatchStatus#COMPLETED : 성공 |
startTime | job을 실행할 때의 시스템 시간을 나타냄 | java.util.Date Type |
endTime | 성공 여부와 상관없이 실행이 종료될 때의 시스템 시간을 나타냄 | java.util.Date |
exitStatus | 실행 결과를 나타내는 ExitStatus, 호출자에게 리턴하는 종료코드를 가지고 있기 때문에 가장 중요 | 아직 Job이 완료되지 않으면 비어 있음 |
createTime | JobExecution이 처음 저장될 때의 시스템 시간 | java.util.Date |
lastUpdated | JobExecution 이 저장된 마지막 시간을 나타냄 | java.util.Date |
executionContext | 실행하는 동안 유지해야 하는 모든 사용자 데이터를 담고 있는 Propertybag | |
failureExceptions | job실행 중 발생한 예외 리스트,job 실패시 예외가 2개 이상 발생하는 경우 유용하다. |
다음은 Spring Batch 가 다음과 같이 Job을 테이블에 관리한다.
Step
은 배치 job의 독립적이고 순차적인 단계를 캡슐화한 도메인 객체
모든 Job은 하나 이상의 JobExecution이 존재하듯, Step은 하나이상의 StepExecution
을 가지고 있다.
StepExecution
은 한 번의 Step 실행 시도를 의미한다.
StepExeuction
은 JobExecution과 유사하게 Step을 실행할 때마다 생성한다. 이전 단계 Step이 실패해서 step을 실행하지 않았다면 exeuction을 저장하지 않는다.
실제 Step이 시작 됐을 때만 StepExecution을 생성한다.
Property | Definition | 기타 |
---|---|---|
Status | 실행상태를 나타내는 BatchStatus 오브젝트. | BatchStatus#STARTED : 실행중 BatchStatus#FAILED : 실패 BatchStatus#COMPLETED : 성공 |
startTime | step을 실행할 때의 시스템 시간을 나타냄 | java.util.Date Type |
endTime | 성공 여부와 상관없이 실행이 종료될 때의 시스템 시간을 나타냄 | java.util.Date |
exitStatus | 실행 결과를 나타내는 ExitStatus, 호출자에게 리턴하는 종료코드를 가지고 있기 때문에 가장 중요 | 아직 Job이 완료되지 않으면 비어 있음 |
lastUpdated | JobExecution 이 저장된 마지막 시간을 나타냄 | java.util.Date |
executionContext | 실행하는 동안 유지해야 하는 모든 사용자 데이터를 담고 있는 Propertybag | |
readCount | 성공적으로 Read한 아이템 수 | |
writeCount | 성공적으로 Write한 아이템 수 | |
commitCount | 실행중에 커밋된 트랜잭션 수 | |
rollbackCount | Step 에서 처리된 트랜잭션 중 롤백된 횟수 | |
readSkipCount | read에 실패해서 스킵된 횟수 | |
processSkipCount | process에 실패해서 스킵된 횟수 | |
filecount | ItemProcessor에 의해 필터링된 아이템 수 | |
writeSkipCount | write에 실패해서 스킵된 횟수 |
ExecutionContext는 프레임워크에서 유지/관리하는 키/값 쌍의 컬렉션
StepExecution
, JobExecution
객체의 상태를 저장한다.
Execution 상태를 저장하고 있어, 재시작에 용이하다 왜냐하면 실패되기전까지의 Context를 저장하고 있기 때문이다.
예를들어 파일을 읽다가 특정 라인에서 에러가 발생했다. 이를 해결하기 위해서는 ExecutionContext에 특정 라인수를 넣어 다시 실행해주면 된다.
다음 예제와 같이 현재 읽은 라인 수를 컨텍스트에 넣기만 하면 나머지는 프레임워크가 다 처리한다.
executionContext.putLong(getKey(LINES_READ_COUNT), reader.getPosition());
좀 더 자세히 설명하자면 다음과 같은 상태로 JOB이 실패가 났다고 생각해보자.
위 테이블들을 설명하자면 다음과 같다.
따라서 40322부터 JobExecution을 재실행시켜줘야 하는데 , 마지막 실행을 가리킨 executionContext를 읽어서 다음실행에 넣어줄 수 있게 구현할 수 있다
// executionContext가 마지막으로 읽은 상태가 있는지 확인하고, 재실행할 수 있도록 세팅해주는 코드.
if(executionContext.containsKey(getKey(LINES_READ_COUNT))) {
log.debug("Initializing for restart. Restart data is: " + executionContext);
long lineCount = executionContext.getLong(getKey(LINES_READ_COUNT));
LineReader reader = getReader();
Object record = "";
while (reader.getPosition() < lineCount && record != null){
record = readLine();
}
}
위 코드를 통해서 중단 됐던 위치로부터 (40322번째) Step을 다시 실행할 수 있다.
JobExecution 당 ExecutionContext가 하나인 것처럼, 모든 StepExecution 마다 ExecutionContext를 하나를 가지고 있다.
ExecutionContext ecStep = stepExeuction.getExecutionContext();
ExecutionContext ecJob = jobExecution.getExecutionContext();
JobRepository
는 위에서 언급된 객체의 모든 영속성을 관리해준다.
즉 JobLauncher
, Job
, Step
구현체에 CRUD 기능을 제공한다.
Job
을 실행할 때 레포지토리에서 JobExeuction
을 조회하고 실행중에는 StepExecution
, JobExecution
구현체를 레포지토리에 넘겨 저장한다.
자바 기반 설정은 @EnableBatchProcessing 어노테이션만 달아주면 JobRepository를 자동으로 컴포넌트로 설정한다 (주입된다)
JobLauncher
는 아래 코드처럼 주어진 JobParameter로 Job을 실행시키는 간단한 인터페이스
public interface JobLauncher {
public JobExecution run(Job job, JobParameters jobParameters)
throws JobExecutionAlreadyRunningException, JobRestartException,
JobInstanceAlreadyCompleteException, JobParametersInvalidException;
}
ItemReader는 Step에서 아이템을 한번에 하나씩 읽어오는 작업을 추상화한 개념, 더이상 읽을 아이템이 없으면 Item Reader는 null을 리턴한다.
ItemWriter는 Step에서 배치나 청크단위로 아이템을 출력하는 작업을 추상화한다. 보통 ItemWriter는 다음에 받을 입력이 무엇인지는 알지 못하고 현재 받은 아이템만 알고있다.
ItemProcessor는 아이템을 처리하는 비즈니스 로직을 나타내는 추상화 개념이다. ItemReade가 아이템을 하나 read하고 ItemWriter가 아이템 묶음을 한다면 ItemProcessor는 데이터 변환이나 다른 비즈니스 처리를 담당한다. 데이터를 처리하던중 아이템이 유효하지 않다고 판단하면 null
을 리턴한다.
Reader, Writer, Processor는 추후 자세한 설명이 곁들여 진다고 한다.
도메인 개념만 읽었을 뿐인데,
배치 프로그램 하나는 짤 수 있을 것 같은 출처를 알 수 없는 자신감이 든다.
그만큼 사용하기 쉬운 도메인 설계를 바탕으로 스프링 배치를 만들었다라는 소리가 아닐까 한다.
열심히 공부해보자
출처 : Spring Batch Document
출처 : 토리맘님의 스프링 배치