티스토리 뷰

Chunk 방식은 정형화된 방식이라면 Tasklet 방식은 비교적 자유로운 방식이다. 따라서 실제로 batch를 사용할때 적어도 내가 경험해본 프로젝트에서는 Tasklet 방식을 훨씬 선호하였다. 이것도 Chunk와 마찬가지로 전에 Xml Config 방식으로 어떻게 사용하는지 살펴본적이 있는데 Springboot 기반의 Batch에서는 어떻게 사용을 하는지 알아보자. 


batch application 구조를 어떻게 잡느냐에 따라 Tasklet을 작성하는 방법은 다양하게 변할 수 있다. (Tasklet 내부를 작성하는건 동일하다. 표현법만 다를 뿐이다..) 필자는 크게 두가지 방법으로 구성을 해봤는데

Job 구성 클래스 외부에 tasklet 클래스를 만들어서 참조하는 방식이 있다. 이것은 tasklet 클래스가 재사용이 될 수 있는 상황에 적절하다.

또 다른 하나는 java lambda 표현식을 써서 이를 축약해서 Job 구성 클래스 내부에 tasklet 구현부를 넣어서 하나의 클래스로 하나의 업무를 정의하는 방식이다. 이것은 간단한 배치를 구현할때 주로 사용한다. 익숙한것으로 사용하면 된다. 

 

Job 구성 클래스 외부에 tasklet 작성하여 참조하는 방식

SampleTasklet.java - Job 구성 클래스

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SampleTasklet {
    
    private static final Logger log = LoggerFactory.getLogger(SampleTasklet.class);

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job sampleTaskletJob(SampleJobListener jobListener, Step sampleTaskletStep) {
        return jobBuilderFactory.get("sampleTaskletJob")
            .incrementer(new RunIdIncrementer())
            .flow(sampleTaskletStep)
            .end()
            .build();
    }

    @Bean
    public Step sampleTaskletStep() {
        return stepBuilderFactory.get("sampleTaskletStep")
            .tasklet(new OuterTasklet())
            .build();
    }
}

앞서 Chunk 방식에서 봤던 것처럼 Job이 있고 Step이 있다. 다른점은 Step에서 chunk() 대신 tasklet()을 사용하는 것이다. tasklet은 OuterTasklet() 이라는 외부 클래스를 사용하여 Tasklet 작업을 정의한다. 

 

 

OuterTasklet.java - 실제 tasklet

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.stereotype.Component;

@Component
public class OuterTasklet implements Tasklet {
    
    private static final Logger log = LoggerFactory.getLogger(OuterTasklet.class);
    
    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        
        //business 업무 시작
        for(int inx = 0 ; inx < 20 ; inx++) {
            log.info("[step1] : " + inx);
        }
         //business 업무 끝
        return RepeatStatus.FINISHED;
    }
}

 

Tasklet 클래스는 기본적으로 Tasklet을 implements 받아서 구현을 해야한다. 그에 따라 execute 메소드를 구현해야하며 execute()는 두가지 인자값을 가지는데 각 항목에 대한 설명은 다음과 같다.

 

contribution - 현재 단계 실행을 업데이트하기 위해 다시 전달되는 변경 가능한 상태

chunkContext - 호출 간에는 공유되지만 재시작 간에는 공유되지 않는 속성

 

Return Type으로는 RepeatStatus를 지정해서 이 Tasklet 업무의 끝을 알려줘야한다. 

 

Job 구성 클래스 에 tasklet 구현하는 방식 (lambda)

SampleTasklet.java

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SampleTasklet {
    
    private static final Logger log = LoggerFactory.getLogger(SampleTasklet.class);

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;
    
    @Bean
    public Job sampleTaskletJob(SampleJobListener jobListener, Step sampleTaskletStep) {
        return jobBuilderFactory.get("sampleTaskletJob")
            .incrementer(new RunIdIncrementer())
            .flow(sampleTaskletStep)
            .end()
            .build();
    }

    @Bean
    public Step sampleTaskletStep(SampleStepListener stepListener) {
        return stepBuilderFactory.get("sampleTaskletStep")
                .tasklet((contribution, chunkContext) -> {
                    //business 업무 시작
                    for(int inx = 0 ; inx < 20 ; inx++) {
                        log.info("[step1] : " + inx);
                    }
                    //business 업무 끝
                    return RepeatStatus.FINISHED;
                })
            .build();
    }
}

메뉴만 거창하게 두가지로 나눠 놓았지만 Job 정의 클래스 내부에서 Tasklet을 구현하느냐 외부에서 구현하느냐 차이이다. 이것은 lambda 표현식으로 간단하게 내부에서 Tasklet을 구현한 것이다. 별도의 부연 설명이 필요 없는것 같다. 

 

 

이 Tasklet을 실행을 하면 다음과 같은 결과가 출력이 된다. 

 

 

이렇게 간단히 Tasklet에 대한 sample을 살펴보았다. 

 

끝!

 

댓글
최근에 올라온 글
최근에 달린 댓글
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31