• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

ThreadPoolTaskExecutor 여러 Job 실행 시 대기 처리

22.01.12 14:59 작성 조회수 956

1

 

안녕하세요, 강사님


@Slf4j
@RequiredArgsConstructor
@Configuration
@EnableBatchProcessing
public class BatchConfig extends DefaultBatchConfigurer {

@Override
public JobLauncher createJobLauncher() throws Exception {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(1);
taskExecutor.setMaxPoolSize(2);
taskExecutor.setQueueCapacity(500);
taskExecutor.afterPropertiesSet();

SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setTaskExecutor(taskExecutor);
jobLauncher.setJobRepository(createJobRepository());
jobLauncher.afterPropertiesSet();
return jobLauncher;
}
//...
}

 

공통으로 Job 관리할때는 JobLauncher에 ThreadPoolTaskExecutor을 등록해서 대기작업을 했습니다.

만약 엑셀 가져오기(업로드), 통계배치 등 배치Job 종류가 여러개이고 따로 관리해야할때,  

엑셀 pool 2개, 통계배치pool 1개 이렇게 따로 pool 을 만들고 싶다면, 어떻게 해야할까요?

Job 종류 마다 JobLauncher 을 여러개 만들어야 하는건가요? 

pool 개수 이상에 요청이 들어오면 대기상태였다가 앞의 배치 작업 끝나면 실행시키는 방식을 생각하고 있습니다.

ex.  엑셀 pool 2개, 통계배치pool 1개 일 경우

    엑셀가져오기 작업 요청이 3번 들어오면 앞의 두 작업은 실행되고 나머지 하나는 대기상태. 

    동시에 다른 통계배치작업 요청이 2번 들어오면 앞의 한 작업은 실행되고 나머지 하나는 대기상태.

 

답변 1

답변을 작성해보세요.

0

스프링 배치에서 JobLauncher 는 초기화시 빈의 형태로 생성이 됩니다.

정확하게는 프록시 객체로 생성이 되고 프록시가 실제 타겟을 호출하는 식으로 이루어집니다.

이 때 프록시가 빈이 된다고 보시면 됩니다.

즉 기본적으로 JobLauncher 는 프록시 빈 한 개가 생성되어 여러 Job 에서 공유하게 됩니다.

그리고 스프링 부트에서는 빈으로 등록된 모든 Job 을 순서대로 실행시키는데 이것을 JobLauncher 에게 위임해서 TaskExecutor 가 처리하도록 합니다. 

이 말 즉 슨 Job 의 종류나 역할에 상관없이 JobLauncher 와 TaskExecutor 가 모든 Job 을 동기 혹은 비동기로 실행하게 됩니다. 

특히 스프링 부트 배치에서는 자동설정 기능에 의해 JobLauncherApplicationRunner 가 모든 Job 을 JobLauncher 에 강제로 전달해 버리기 때문에 Job 의 종류에 따라 JobLauncher 를 다르게 선택하거나 TaskExecutor 를 구분해서 실행하도록 컨트롤 할 수는 없을 것 같습니다.

그래서 질문 하신 내용대로 처리가 이루어질려면 빈으로 등록된 Job 들 중에서 원하는 Job 을 DI 받고 하나의 JobLauncher 와  TaskExecutor 를 공유하는 것이 아닌 Job 마다 독립적으로 생성 및 할당해서 적용되도록 구성해야 할 것 같습니다.

그리고 TaskExecutor 변수가 멤버 변수이기 때문에 런타임 시점에 TaskExecutor 구현체를 JobLauncher 에 전달해서 적용하는 전략패턴을 쓰면 Job 마다 Pool 의 설정을 독립적으로 가져 갈 수 없는 문제가 발생해서 이것도 해결책은 될 수 없습니다.

만약 Job 마다 별도의 jar 로 만들어 사용한다면 하나의 JobLauncher 를 사용하고 TaskExecutor 만 변경하도록 할 수 있을 것 같습니다.
리플렉션을 사용한다면 배치를 실행할 때 
TaskExecutor 의 구현클래스 풀네임을 실행 인자로 전달해서 동적으로 클래스를 로드하고 객체를 만들어 JobLaucher 에 전달해서 사용하도록 할 수 도 있는데 코드가 복잡해 질 수 있고 그리 추천할 만한 방법은 아닙니다.

혹 다른 방법이 있는지 저도 계속 고민해 보겠습니다.^^