Spring-boot Batch Job ๊ด๋ จ ๋ด์ฉ๋ค์ด๋ค.
Spring batch๊ฐ ์คํ๋๊ธฐ ์ํด์๋ ๋ฉํ๋ฐ์ดํฐ ํ
์ด๋ธ์ด ํ์๋ก ์กด์ฌํด์ผ ํ๋ค.
๋ฉํ๋ฐ์ดํฐ ํ
์ด๋ธ์ ์ฌ์ฉํ๋ DB์์ ํ
์ด๋ธ์กฐํ๋ฅผ ํตํด ๋ณผ ์ ์๋ค.
๊ฐ ํ
์ด๋ธ์ ์ญํ ์ ์์๋ณด์.
BATCH_JOB_INSTANCE
BATCH_JOB_INSTANCE
์ ์์ฑ๋๋ค.Job Parameter๋
java -jar *.jar $PARAM=$VALUE
๋ก ๋ฃ์ด์ค๋ค.
BATCH_JOB_EXECUTION
BATCH_JOB_INSTANCE
์ child ๊ด๊ณBATCH_JOB_INSTANCE
์ ์ฑ๊ณต/์คํจ์ ๋ด์ญ์ ๊ฐ์ง๊ณ ์๋ค.BATCH_JOB_EXECUTION_PARAMS
BATCH_JOB_EXECUTION
์ด ์์ฑ๋ ๋น์ ์
๋ ฅ๋ฐ์ Job Parameter๋ฅผ ๋ด๊ณ ์๋ค.Job์ ์ ์ํ ์ ์๋ JobBuilderFactory
์ ๋ํด ์์๋ณธ๋ค.
start($STEP_METHOD)
next($STEP_METHOD)
์กฐ๊ฑด์ ๋ฐ๋ผ ๋ถ๊ธฐํ์ฌ ์๋ก ๋ค๋ฅธ step์ ์คํํ๋ ๊ฒฝ์ฐ ์ฌ์ฉํ๋ค.
@Bean
public Job stepNextConditionalJob(){
return jobBuilderFactory.get("setpNextConditionalJob")
.start(conditionalJobStep1())
.on("FAILED") // if FAILED
.to(conditionalJobStep3()) // step3๋ก ์ด๋
.on("*") // step3์ ๊ฒฐ๊ณผ์ ๊ด๊ณ ์์ด
.end() // step3์ผ๋ก ์ด๋ ํ flow ์ข
๋ฃ
.from(conditionalJobStep1()) // step1๋ก๋ถํฐ
.on("*") // FAILED์ธ ๋ชจ๋ ๊ฒฝ์ฐ
.to(conditionalJobStep2()) // step2๋ก ์ด๋
.next(conditionalJobStep3()) // step2 ์ ์ ์ข
๋ฃ ํ step3์ผ๋ก ์ด๋
.on("*") // step3์ ๊ฒฐ๊ณผ์ ๊ด๊ณ ์์ด
.end()
.end()
.build();
}
on()
to()
from()
end()
on()
๋ค์ ์๋ end()
๋ FlowBuilder๋ฅผ ๋ฐํํ๋ค.build()
์์ ์๋ end()
๋ FlowBuilder๋ฅผ ์ข
๋ฃํ๋ค.Spring Batch์์๋ ์ธ/๋ด๋ถ์์ Job Parameter๋ฅผ ๋ฐ์ Batch Component์์ ์ฌ์ฉํ ์ ์๊ฒ ์ง์ํ๋ค.
Job Parameter๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์ , ํญ์ Spring Batch Scope๋ฅผ ์ ์ธํด์ผ ํ๋ค.
Spring Batch Scope๋
@StepScope
์@JobScope
๋ฅผ ์ง์นญํ๋ค.
@Value("#{jobParameters[ํ๋ผ๋ฏธํฐ๋ช
]}")
@JobScope
: Step
์ ์ธ์์ ์ฌ์ฉํ๋ค.
@StepScope
: Tasklet, ItemReader, ItemWriter, ItemProcessor
์ ์ธ์์ ์ฌ์ฉํ๋ค.
@Bean
public Job scopeJob() {
return jobBuilderFactory.get("scopeJob")
.start(scopeStep1(null))
.next(scopeStep2())
.build();
}
@Bean
@JobScope
public Step scopeStep1(@Value("#{jobParameters[requestDate]}") String requestDate) {
return stepBuilderFactory.get("scopeStep1")
.tasklet((contribution, chunkContext) -> {
log.info(">>>>> This is scopeStep1");
log.info(">>>>> requestDate = {}", requestDate);
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Step scopeStep2() {
return stepBuilderFactory.get("scopeStep2")
.tasklet(scopeStep2Tasklet(null))
.build();
}
@Bean
@StepScope
public Tasklet scopeStep2Tasklet(@Value("#{jobParameters[requestDate]}") String requestDate) {
return (contribution, chunkContext) -> {
log.info(">>>>> This is scopeStep2");
log.info(">>>>> requestDate = {}", requestDate);
return RepeatStatus.FINISHED;
};
}
scopeStep1(null)
, scopeStep2Tasklet(null)
null
์ ํ ๋นํ๋ค.@StepScope
๋ Step ์คํ ์์ ์ Bean์ด ์์ฑ๋๋ค.
๋ง์ฐฌ๊ฐ์ง๋ก @JobScope
๋ Jop ์คํ ์์ ์ Bean์ด ์์ฑ๋๋ค.
์ฆ, Bean์ ์์ฑ ์์ ์ ์ง์ ๋ Scope๊ฐ ์คํ๋๋ ์์ ์ผ๋ก ์ง์ฐ์ํจ๋ค.
MVC์ request scope๊ฐ request/resoponse์ Bean์ด ์์ฑ/์ญ์ ๊ฐ ๋๋ ๊ฒ ์ฒ๋ผ JobScope. StepScope์ญ์ Job์ด ์คํ๋๊ณ ๋๋ ๋, Step์ด ์คํ๋๊ณ ๋๋ ๋ ์์ฑ/์ญ์ ๊ฐ ์ด๋ฃจ์ด์ง๋ค.
์ด ๊ธฐ๋ฅ์ ํตํด ๋ค์๊ณผ ๊ฐ์ ์ฅ์ ์ ๊ฐ์ง๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ๋ฑ๋ก๋์ด์ง ๋ชจ๋ job์ด ์คํ๋๋ค.
์ํ๋ batch job๋ง ์คํํ๊ณ ์ถ์ ๊ฒฝ์ฐ ์ฌ์ฉํ๋ค.
application.yml
Program arguments๋ก job.name
์ด ๋์ด์ค๋ฉด ํด๋น ๊ฐ๊ณผ ์ผ์นํ๋ job๋ง ์คํํ๋ ์ต์
job.name
์ด ์์ผ๋ฉด job.name
ํ ๋น, ์์ผ๋ฉด NONE
ํ ๋นspring.batch.job.names: ${job.name:NONE}
๋ค์์ Program arguments๋ฅผ ์ ์ธํ๋ ๋ฐฉ๋ฒ์ด๋ค.
java -jar *.jar --job.name=stepNextJob
java -jar *.jar version=1 --job.name=stepNextJob
version=1
--job.name
application.yml
์ job.name
์ stepNextJob์ด๋ผ๋ ๊ฐ์ ํ ๋นํด์ค๋ง์ฝ ์ธ๋ถ์์ ๋๊ฒจ์ฃผ๋ ํ๋ผ๋ฏธํฐ์ ๋ฐ๋ผ Batch๊ฐ ๋ค๋ฅด๊ฒ ์คํ๋๋ ์์ ์ด๋ค.
๊ทธ๋ฌ๋ ์น์๋ฒ์์ Batch๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ ๊ถ์ฅ๋์ง ์๋๋ค.
@Slf4j
@RequiredArgsConstructor
@RestController
public class JobLauncherController {
private final JobLauncher jobLauncher;
private final Job job;
@GetMapping("/launchjob")
public String handle(@RequestParam("fileName") String fileName) throws Exception {
try {
JobParameters jobParameters = new JobParametersBuilder()
.addString("input.file.name", fileName)
.addLong("time", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(job, jobParameters);
} catch (Exception e) {
log.info(e.getMessage());
}
return "Done";
}
}
๋ชจ๋ ์์ค๋ ๊นํ๋ธ์ ์ฌ๋ ค๋์๋ค.
์ฐธ๊ณ ๋งํฌ: jojoldu ๋ธ๋ก๊ทธ