Job에는 여러 Step이 있다. Step은 실질적으로 요청을 처리하는 객체이다. Step은 Job과 마찬가지로 행위에 대한 명세서이다. 1개의 Job에는 여러개의 Step을 포함할 수 있고 따라서 1개의 JobExecution에는 여러개의 StepExecution을 포함할 수 있다.
예시)
- Job: 식당을 예약한다.
- Step 1: 식당에 전화한다.
- Step 2: 예약한다.
- Step 3: 예약금을 송금한다.
StepExecution
Step이라는 명세서를 실행시켜 실행된 기록을 StepExecution이라고 한다. JobExecution이 Job의 실행 정보를 가지고 있는것처럼, StepExecution은 Step의 실행 정보를 가지고 있다. 다음과 같은 메서드들을 StepExecution은 가지고 있다.
- getStepName() → Step의 이름
- getJobExecution() → JobExecution
- getStartTime() → Step의 시작 시간
- getEndTime() → Step의 종료 시간
- getExecutionContext() → ExecutionContext
- getExitStatus() → Step의 실행 결과
- getStatus() → Step의 현재 실행 상태(Batch Status)
StepExecutionContext
JobExecutionContext가 1개의 Job에서 공유하는 공간이면, StepExecutionContext는 1개의 Step 내에서 공유하는 공간(Context)이다.
PlatformTransactionManager
StepBuilder로 Step을 정의할 때, transactionManager를 받을 수 있다. @EnableBatchProcessing을 추가하면 아래와 같이 기본 transactionManager를 사용할 수 있다. (다만, 프로젝트에서 datasource가 여러개인 경우에는, 다른 말로, 데이터베이스를 여러개 사용한다면, 직접 별도로 transactionManager를 만들어서 사용해야 한다)
@Autowired
PlatformTransactionManager transactionManager;
transactionManager를 StepBuilderFactory에 추가하면, 해당 Step은 transactionManager를 사용해서 내부의 transaction을 관리한다.
TransactionManager란, 데이터베이스 트랜잭션은 데이터베이스의 데이터가 변하는 과정이 독립적이며, 일관되고 믿을 수 있는걸 보장하는 것을 말한다. 예를 들면, A가 B에게 송금을 했을 때, A는 돈이 보내져서 계좌에서 돈이 빠졌는데, B는 어떤 에러가 발생해서 돈을 받지 못했다. 만약, 이것이 트랜잭션으로 관리가 됐다면 이런일은 일어나지 않았을 것이다. 두 과정을 1개의 트랜잭션으로 묶었다면, B가 돈을 받지 못하면 A의 돈도 빠져나가지 않았던 것이 된다. 바로 이런 트랜잭션을 관리해주는 것이 바로 트랜잭션 매니저이고 @EnableBatchProcessing을 통해 자동으로 기본 트랜잭션 매니저를 만들어 준다.
@JobScope
일반적으로, Scope를 지정하지 않는다면 처음 스프링부트가 시작될 때 모든 Bean이 생성된다. Step을 생성하는 코드에 @JobScope 애노테이션을 달면, Step을 스프링 부트가 시작될 때 바로 만드는 것이 아니라 연관된 Job이 Step을 실행하는 시점에 만들어준다. Lazy Loading과 비슷한 개념이라고 보면 된다.
1개의 스프링 배치 애플리케이션에 Job1, Job2, Job3이 있고, 3개의 Job들에 연결된 Step도 많이 만들어 두었는데, Job1만 실행시킨다면 Job1과 연관되지 않는 Step들은 굳이 만들 필요가 없다. 굳이 필요도 없는 Step을 만드는데 리소스나 시간을 낭비할 필요가 없기 때문에 이 @JobScope는 꽤나 중요하다. 또 다른 이유로는, Job이 실행된 다음에 나중에 결정되는 값이 있다면 늦게 Step을 생성하고 싶을 것이다. 예를 들면 다음과 같은 Job과 Step이 있다고 해보자.
- Job1 → Step1.1 - Step1.2 - Step1.3
Job1은 세 개의 스텝으로 구성되어 있는데 Step1.2는 Step1.1의 결과를 통해 얻어낸 데이터를 가지고 Step1.2를 만들어야 한다면, Step1.2는 미리 만들수가 없다. Step1.1을 실행하고 나서 Step1.2을 만들어야 하기 때문에도 @JobScope를 사용하면 좋다.
결론은, 일반적으로는 @JobScope를 사용하면 좋다.
정리를 하자면
이번 포스팅에선 Step에 대해 알아보았다. 다음 포스팅은 Tasklet에 대해 알아보자!
'Spring Batch' 카테고리의 다른 글
ItemReader (1) | 2024.10.09 |
---|---|
Chunk Processing (5) | 2024.10.09 |
Tasklet (0) | 2024.10.09 |
Job (7) | 2024.10.09 |
Spring Batch 구조와 핵심 키워드 (2) | 2024.10.09 |