2023. 12. 4. 02:18ㆍSpring 기초
Intro
이번 포스팅에서는 Spring Batch가 지원하는 Job Parameter에 대해 다룹니다.
간단한 사용법과 Spring Batch가 Job Paramter를 재사용하는 문제에 대해서도 다룹니다.
잘못된 부분은 언제든지 말씀해주세요 ~
1. Job Parameter란
말 그대로, Batch Job을 실행할 때 외부/내부에서 주입받아 Batch 컴포넌트 내에서 사용할 수 있는 파라미터입니다.
코드의 배포 없이 Chunk Size를 변경하고 싶다거나, 엊그제 고장나서 실행이 안된 Batch를 다시 돌리고 싶을 때 사용할 수 있습니다.
첫번째의 경우 Chunk Size를 파라미터로 주입받고, 두번째의 경우 실행 기준 날짜를 파라미터로 주입받으면 되는 것이죠~
2-1. Job Parameter 사용법(1)
사용법은 아래와 캡쳐와 같이 Spring Batch 전용 Scope(@JobScope, @StepScope) 하위에서 SpEL로 선언해서 사용하면 됩니다.
Spring Batch에서는 기본적으로 제공되는 scope(request, session, singleton 등) 외에 Job, Step이라는 추가적인 scope이 제공됩니다. 이 작업단위별로 scope을 지정해 작업 수행이 가능합니다. 즉, Bean의 생명주기를 Job이나 Step이 실행될 때 생성되도록 설정이 가능하다는 뜻입니다.
Bean의 Default scope는 Singleton으로, 처음에 초기화된 Singleton Bean은 더이상 재정의 되지 않습니다. 따라서 Job을 실행할 때 다른 Job Parameter를 넘겨줘도 의도대로 동작하지 않습니다. 따라서 @JobScope 또는 @StepScope을 통해 Bean을 등록해야 합니다.
같은 맥락에서, 호출하는 쪽에 파라미터 값으로 null을 할당해도 가능한 이유도 설명이 가능합니다.
JobParameter는 애플리케이션 실행시에 할당되는 것이 아니라 Job과 Step이 실행될 때 생성되는 Bean들과 함께 할당되기 때문입니다.
2-2. Job Parameter 사용법(2)
저는 위의 방법보다, 아래의 방법을 이용해서 Job Paramter를 주입받습니다.
먼저 Job Paramter를 담을 클래스를 생성합니다. Job Paramter로 maxItemCount와 ChunkSize를 주입받도록 하겠습니다.
maxItemCount는 Batch를 실행할 Item의 개수입니다. maxItemCount 개수의 아이템이 처리되면 Batch가 종료되도록 하였습니다.
AbstractPagingItemReader를 구현하면 쉽게 가능합니다(자세한 설명은 생략)
동일한 방법으로 JobParamter를 주입받습니다. 위에서 언급했듯 @JobScope는 필수입니다.
요렇게 설정하면 생성자를 통해 자동으로 값을 주입받을 수 있습니다.
이후에는 Bean으로 등록된 JobParameter 클래스에서 값을 꺼내 사용할 수 있습니다.
이렇게 JobParameter를 @Bean으로 선언하면, 해당 JobParameter 클래스를 다른 Job에서도 사용할 수 있습니다. 위의 이미지 중 파란색 네모 박스에 설정할 Bean name 만 달리하면 가능하겠죠. 저는 클래스명의 범용성이 떨어져서 안될 것 같네요.
3. Job Parameter를 재사용하는 문제
RunIdIncrementer를 이용할 경우 같은 Job이 직전 실행에 사용한 파라미터가 재사용되는 버그가 존재합니다.
직전에 사용한 파라미터 중 하나가 다음 실행시 누락되면 이전의 파라미터를 재사용하게 되는 것입니다..
예를들어, 12월 4일에 돌아야 하는 Batch가 모종의 이유로 고장이 난 상황이라고 가정해보겠습니다.
2023-12-04를 targetDate라는 파라미터로 전달해 Batch를 한 번 실행하면 이 문제는 금방 해결할 수 있습니다.
위와 같이 targetDate라는 파라미터를 전달하고 Local에서 Batch를 실행하면,
아래처럼 targetDate 파라미터가 잘 주입이 되는 것을 확인할 수 있습니다.
Spring Batch의 메타테이블인 batch_job_execution_params에서도 Job에 사용된 파라미터를 확인할 수 있습니다.
이제 문제가 해결되었으니 Batch Job을 실행할 때 12월 4일로 설정한 targetDate를 제거해야합니다. 그래야 오늘 날짜에 해당하는 데이터를 대상으로 Batch가 실행되기 때문이죠
RunIdIncrementer 답게 run.id가 1 증가한 모습을 확인할 수 있습니다. 그런데, 이번에는 사용하지 않은 targetDate가 나타났습니다.
당연히 batch_job_execution_params 테이블에도 targetDate가 들어있었습니다.
결론부터 말씀드리면 RunIdIncrementer의 동작 방식때문에 그렇습니다.
이 재사용 문제를 막기 위해서는 새로운 Incrementer를 구현해야 합니다.
설명에 따르면 previous job parameter가 인자로 넘어온다고 합니다.
이 previous job parameter는 getNext() 내부에서 일련의 가공을 거쳐 새로운 JobParamter로 다시 탄생하게 됩니다.
위의 getNext()를 호출하는 부분은 아래와 같습니다.
1번에서 Job의 이름으로 바로 직전에 실행한 JobInstance를 메타 테이블에서 가져옵니다.
2번에서는 가장 마지막에(최근에) 실행한 JobInstance를 조회한 뒤 당시에 사용한 Parameter를 incrementer의 인자로 넣어주는 모습입니다.
아무튼 Incremeter를 새로 구현하면 파라미터를 재사용하는 문제를 해결할 수 있습니다.
위 getNext()에 파라미터로 전달되는 JobParameter parameters는 이전에 사용한 파라미터임을 확인했습니다.
따라서 다른 파라미터들은 거들떠보지도 않고, 이전에 사용했던 run.id에 1을 더해 새로운 파라미터를 만들어주도록 하였습니다.
REF
'Spring 기초' 카테고리의 다른 글
SpringBoot + GraphQL (2/2) (0) | 2023.07.22 |
---|---|
SpringBoot + GraphQL (1/2) (0) | 2023.07.13 |
Openfeign으로 외부 API 호출하기 (1) | 2023.05.28 |
WebSocket & STOMP 그룹 채팅방 구현하기 (4) | 2023.05.16 |
[SpringBoot] Annotation을 이용해 Slack에 Error log 남기기 (0) | 2023.03.18 |