Spring Batch : TaskLetStep 관련 정리

    Spring Batch, TaskletStep이란? 

    TaskLetStep은 내부적으로 TaskLet을 가지는 객체다. TaskLet은 실제 일을 하는 객체이며, 쓰레드의 Runnable 인터페이스와 유사한 역할을 한다. TaskLetStep은 또 내부적으로 RepetableTemplate 객체를 가지는데, 이 객체를 통해 TaskLet을 기본적으로는 무한대로 반복하는 형태의 동작을 한다. TaskLetStep은 TaskLet 기반도 가능하지만, Chunk를 기반으로 가능하다. 

     

    TaskLetStep은 기본적으로 무한히 반복하는 형태로 동작을 하는데, 단 한번만 동작하기 위해서는 TaskLet 객체를 반환할 때 RepeatStatus.Finished / null값을 반환하면 단 한번만 반복한다. 

     

    TaskLetStep 반복 실행 여부

    • RepeatStatus.Finished : null값 반환 시, 자동으로 이렇게 변환. 한번만 수행하고 종료함.
    • RepeatStatus.Conitnuable : Tasklet 반복함. 

    TaskLetStep은 내부에 Repeat 템플릿을 가져서 가지고 있는 객체를 반복해서 수행한다. 다만, 이것은 설정으로 바꿀 수 있다. TaskLet이 반환하는 객체의 값을 수정하면서 무한반복 / 1회 진행으로 바꿔서 이야기 할 수 있다. 

     


    TaskLetBuilder의 Tasklet()

    TaskLetBuilder는 TaskLet() API를 제공한다. TaskLetStep에서 사용할 Tasklet 객체를 설정하는 메서드다. 여러번 사용할 수 있는 것처럼 보이는데, TaskLetStep은 단 하나의 TaskLet만 수행한다. 따라서 여러 번 TaskLet() 메서드를 사용했다면, 가장 마지막에 지정된 TaskLet 객체만 실제로 수행된다. 

     

     


    TaskLet 기반 / Chunk 기반의 TaskLetStep의 차이

    TaskLet 기반 TaskLetStep

    TaskLet기반의 TaskLetStep은 다음과 같이 TaskLet 객체가 가지는 한 가지 비즈니스 로직을 수행하는 역할을 한다. 

    Chunk 기반 TaskLetStep

    Chunk 객체는 내부적으로 ItemReader, ItemProcessor, ItemWriter를 가지고 이들 객체 간의 상호작용을 바탕으로 비즈니스 로직이 수행된다. 정리하면 TaskLet 기반은 단일 객체를 바탕으로 비즈니스 로직을 수행하고, Chunk 기반은 ItemReader, ItemProcessor, ItemWriter로 나누어져 객체가 기능을 수행하는 것으로 이해할 수 있다. 

     

    Spring Batch, TaskletStep 코드 확인

    TaskLetStep은 다음과 같이 stepBuilderFactory로 부터 StepBuilder를 받은 후, StepBuilder 객체에 taskLet() 메서드를 사용하면서 만들 수 있다. 

    StepBuilder 객체는 tasklet() 메서드를 통해 TaskLetStepBuilder를 전달해준다. 이 때, 내부적으로 만든 tasklet 익명 클래스를 전달해서 TaskLetStepBuilder가 가지게 된다. 이후, Build를 통해 TaskLetStepBuilder는 TaskLetStep을 만든다. 

     

     

    Spring Batch, TaskletStep 실행 관점

    TaskLetStep은 SimpleJobLauncher를 실행하면서, SimpleJob이 실행시켜준다. SimpleJob의 doExecute에서 for문을 돌면서 각 Step을 실행시켜준다. 이 때, handleStep 메서드에 Step / Execution 정보를 넘겨주면서 실행된다. 

    handlStep 메서드는 stepHandler 객체에 step, Exeuction 매개변수를 넘겨주면서 Step을 실행하고, 그 실행 결과로 StepExecution을 반환해준다. 이 때, stepHandler의 타입은 StepHandler 인터페이스다. 실제 구현체는 SimplStepHandler가 된다.

    SimplStepHandler의 handleStep 메서드는 step.execute()를 통해 Step을 실행시켜준다. 이 때, execute는 abstractStep으로 가게 되는데 추상 클래스이기 때문에 실제로 메서드를 수행하는 것은 TaskLetStep 객체가 된다. 

    TaskLetStep 객체는 내부적으로 RepeatTemplate()을 가지고 있어서, 반복 스텝 수행을 제어하는 것을 알 수 있다. TaskLetStep의 doExecute 메서드를 통해서 Step이 실행되게 되는데, 이 때 iterate 메서드를 통해서 doInChunkContext 메서드로 들어간다. 

    doInChunkContext 메서드에서는 TrasnactionTemplate을 만들고 Execute를 통해 Step을 실행시켜준다. 이걸 보고, TaskLetStep은 Transaction 처리 없이 자동으로 Transaction 내에서 비즈니스 로직이 수행되는 것을 이해할 수 있다.

    trasacationTemplate의 execute 메서드에서는 내부적으로 action.doInTransaction을 통해 Step을 실행시켜주는 단계로 넘어가는 것을 볼 수 있다. 

    다시 TaskLetSTep의 doInTransaction 메서드로 들어오게 된다. 여기서 RepeatStatus를 Contiunable로 설정하는 것을 볼 수 있다. 이 말은 RepeatStatus.Finished를 설정하지 않으면, 항상 무한 반복한다는 뜻이다. 

    Step 실행 전에 beforeChunk를 통해 ChunkListner가 필요한 일을 하는 것을 확인할 수 있다. 

    TaskLet.Execute()를 통해 TaskletStep이 가지는 TaskLet 객체의 비즈니스 로직이 수행되는 것을 확인할 수 있다. 결과는 result에 저장되는데, result에 null값이 전달될 경우 RepeatStatus가 Finished로 설정되어 반복되지 않는 것을 확인할 수 있다. 

    TaskLetStep 객체의 실행이 끝나면, 다시 doInChunkContext 메서드로 돌아온다. 여기서 ChunkListner.afterChunk를 통해 다시 한번 필요한 일을 하는 것을 확인할 수 있다. 

     


    TaskLet이 제공하는 API

    • startLimit → Step의 실행 횟수를 설정, 설정한만큼만 실행. 그 이상 실행 시, 예외 발생. 기본값은 INF.
    • allowStartIfComplete → Step을 항상 실행하고자 할 때 설정.
    • listener → Step 전후로 필요한 작업을 하는 기능을 지원해줌. 

    TaskLet 메서드를 통해 반환받은 TaskLetBuilder는 위 세 가지 API를 지원한다. 헷갈릴 수 있는데, stratLimit은 Step이 실행될 수 있는 최대 횟수를 이야기한다. Step은 주로 실패할 경우 다시 시작할 수 있는데, 이 시작횟수가 제한되는 것으로 이해할 수 있다. 

    AlloStartIfComplete는 항상 Step을 재 시작하고자 할 때 설정할 수 있다. 여러 개의 Step을 가진 Job은 Step 하나가 실패하면, 다시 실행할 수 있다. Job이 다시 실행할 때, 성공한 Step은 기본적으로 재시작을 하지 않고 실패한 Step부터 다시 실행한다. 그렇지만 AllowStartIfComplete를 true로 설정하면, 성공한 Step도 항상 다시 시작한다. 이런 Step이 필요한 시점은 주로 Validation을 하는 Step으로 이해하면 될 것 같다.

     

     

    TaskLetStep 순서도

    TaskletStep은 다음과 같이 동작한다. 위에 코드 설명을 클래스로 나누어보면 다음과 같다고 이해하면 될 것 같다. 결국 SimpleJob이 Step을 실행시키고, 이 Step은 내부적으로 RepeatTemplate을 이용해서 TaskLet을 실행시킨다. 가만히 놔두면 무한 반복이 되는데 Exception이 터지거나, RepeatStatus가 Finished / null로 설정될 경우 Step이 종료된다. 또한, Transaction을 가지고 있기 때문에 Transaction을 처리해줄 필요가 없다. 

     

    Job ↔ TaskLetStep의 그래프

    Job → TaskLetStep의 실행 순서는 다음과 같이 실행된다.

    1. Job이 HandleStep을 통해 Step을 실행시킨다. 이 때, StepExeuction / ExecutionContext가 생성된다. 이 때, Step이 시작되기 때문에 배치 상태를 Started / ExitStatus를 Executing으로 셋팅해준다.
    2. TaskLet으로 넘어가 BeforeStepListener를 수행한다.
    3. RepeatTemplate의 값을 확인해서 RepeatStatus가 Continuable인 경우 Tasklet을 수행한다.
    4. RepeatStatus를 Finished로 수정해서 반환한다. 그리고 이 때, Step Listner의 After Task를 수행해준다.
    5. 모든 것이 수행되었으면 ExitStatus에 현재 상태를 업데이트 해준다.

    댓글

    Designed by JB FACTORY