๐ ExecutionContext
์ง๋ ์๊ฐ์๋ Step, StepExecution์ ๋ํด ์ดํด๋ณด์์ต๋๋ค.
์ด๋ฒ ์๊ฐ์๋ JobExecution ๋ฐ StepExecution ๊ฐ์ฒด์ ์กด์ฌํ๋ ExecutionContext์ ๋ํด ์ดํด๋ณด๊ฒ ์ต๋๋ค.
(์์ ์ฝ๋๋ GitHub์์ ํ์ธํ ์ ์์ต๋๋ค. ๐)
๐ ํด๋น ํฌ์คํ ์ ๋ชฉํ
- Spring Batch ExecutionContext (JobExecution, StepExecution)
๐ ExecutionContext
๊ธฐ๋ณธ ๊ฐ๋
- Spring Batch ํ๋ ์์ํฌ์์ ์ง์ํ๋ key/value ํ์ ๊ณต์ ๊ฐ์ฒด๋ก Job์ ์คํํ๋ฉด์ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๊ณต๊ฐ
- ๊ณต์ ๋ฒ์
- Job ๋ฒ์ - ๊ฐ Job์ JobExecution์ ์ ์ฅ๋๋ฉฐ ์๋ก ๋ค๋ฅธ Job ๊ฐ์๋ ๊ณต์ ๊ฐ ์๋์ง๋ง ๋์ผํ Job ๋ด์ ์๋ก ๋ค๋ฅธ Step ์ฌ์ด์์๋ ๋ฐ์ดํฐ ๊ณต์ ๊ฐ ๊ฐ๋ฅ
- Step ๋ฒ์ - ๊ฐ Step์ StepExecution์ ์ ์ฅ๋๋ฉฐ Step ์ฌ์ด์์๋ ๋ฐ์ดํฐ ๊ณต์ ๋ถ๊ฐ๋ฅ
โป ExecutionContext๋ JobExecution ๋ฐ StepExecution์ ํ๋์ ์กด์ฌํฉ๋๋ค.
public class JobExecution extends Entity {
private final JobParameters jobParameters;
private JobInstance jobInstance;
private volatile Collection<StepExecution> stepExecutions = Collections.synchronizedSet(new LinkedHashSet<>());
...
private volatile ExecutionContext executionContext = new ExecutionContext();
}
public class StepExecution extends Entity {
private final JobExecution jobExecution;
private final String stepName;
private volatile BatchStatus status = BatchStatus.STARTING;
...
private volatile ExecutionContext executionContext = new ExecutionContext();
}
์์ ์ฝ๋
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | @RequiredArgsConstructor @Configuration public class ExecutionContextConfiguration { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; private final ExecutionContextTasklet1 executionContextTasklet1; private final ExecutionContextTasklet2 executionContextTasklet2; private final ExecutionContextTasklet3 executionContextTasklet3; private final ExecutionContextTasklet4 executionContextTasklet4; @Bean public Job executionContextJob() { return this.jobBuilderFactory.get("executionContextJob") .start(executionContextStep1()) .next(executionContextStep2()) .next(executionContextStep3()) .next(executionContextStep4()) .build(); } @Bean public Step executionContextStep1() { return stepBuilderFactory.get("executionContextStep1") .tasklet(executionContextTasklet1) .build(); } @Bean public Step executionContextStep2() { return stepBuilderFactory.get("executionContextStep2") .tasklet(executionContextTasklet2) .build(); } @Bean public Step executionContextStep3() { return stepBuilderFactory.get("executionContextStep3") .tasklet(executionContextTasklet3) .build(); } @Bean public Step executionContextStep4() { return stepBuilderFactory.get("executionContextStep4") .tasklet(executionContextTasklet4) .build(); } } | cs |
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 32 | @Slf4j @Component public class ExecutionContextTasklet1 implements Tasklet { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { ExecutionContext jobExecutionContext = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext(); ExecutionContext stepExecutionContext = chunkContext.getStepContext().getStepExecution().getExecutionContext(); String jobName = chunkContext.getStepContext().getStepExecution().getJobExecution().getJobInstance().getJobName(); String stepName = chunkContext.getStepContext().getStepExecution().getStepName(); log.info("ExecutionContextTasklet1 JobName: {}", jobExecutionContext.get("jobName")); log.info("ExecutionContextTasklet1 StepName: {}", stepExecutionContext.get("stepName")); // Job ExecutionContext์ ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ ์ ์ฅ if (jobExecutionContext.get("jobName") == null) { jobExecutionContext.put("jobName", jobName); } // Step ExecutionContext์ ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ ์ ์ฅ if (stepExecutionContext.get("stepName") == null) { stepExecutionContext.put("stepName", stepName); } log.info("ExecutionContextTasklet1 JobName: {}", jobExecutionContext.get("jobName")); log.info("ExecutionContextTasklet1 StepName: {}", stepExecutionContext.get("stepName")); return RepeatStatus.FINISHED; } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | @Slf4j @Component public class ExecutionContextTasklet2 implements Tasklet { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { ExecutionContext jobExecutionContext = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext(); ExecutionContext stepExecutionContext = chunkContext.getStepContext().getStepExecution().getExecutionContext(); // Tasklet1์์ ExecutionContext ๊ณต๊ฐ์ ์ ์ฅํ ๋ฐ์ดํฐ ์กฐํ(Job ๋ด์ Step๋ค์ ๋ฐ์ดํฐ ๊ณต์ ๊ฐ๋ฅ) log.info("ExecutionContextTasklet2 JobName: {}", jobExecutionContext.get("jobName")); log.info("ExecutionContextTasklet2 StepName: {}", stepExecutionContext.get("stepName")); String stepName = chunkContext.getStepContext().getStepExecution().getStepName(); if (stepExecutionContext.get("stepName") == null) { stepExecutionContext.put("stepName", stepName); } return RepeatStatus.FINISHED; } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @Component public class ExecutionContextTasklet3 implements Tasklet { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { Object name = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().get("name"); // ์์ธ ๋ฐ์ ์ ์ดํ Step์ ์คํ X if (name == null) { chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().put("name", "user1"); throw new RuntimeException("step has failed"); } return RepeatStatus.FINISHED; } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 | @Slf4j @Component public class ExecutionContextTasklet4 implements Tasklet { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { log.info("name: {} ", chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().get("name")); return RepeatStatus.FINISHED; } } | cs |
์์ ์ฝ๋๋ 4๊ฐ์ Tasklet ๊ตฌํ์ฒด ํด๋์ค์ 1๊ฐ์ Job, Step, Tasklet ์ค์ ํด๋์ค์ ๋๋ค.
์ ๊ธฐ๋ณธ ๊ฐ๋ ์์ ๋ง์๋๋ ธ๋ JobExecution์ ๊ฒฝ์ฐ ์๋ก ๋ค๋ฅธ Job๋ค ์ฌ์ด์์๋ ๊ณต์ ๊ฐ ์๋์ง๋ง ๋์ผํ Job ๋ด์ Step๋ค ์ฌ์ด์๋ ๋ฐ์ดํฐ๊ฐ ๊ณต์ ๋๋ค๊ณ ๋ง์์ ๋๋ ธ์๋๋ฐ์, ์ ์์ ์ฝ๋๋ฅผ ํตํด ์ค์ ๋ฐ์ดํฐ๊ฐ ๊ณต์ ๋๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
ExecutionContextConfiguration
- Job, Step, Tasklet ๊ตฌ์ฑ ๋ฐ build
ExecutionContextTasklet1
- ์ต์ด ์คํ๋๋ Tasklet์ผ๋ก JobExecution ๋ฐ StepExecution ๋ด์ ์กด์ฌํ๋ ExecutionContext์ key๊ฐ jobName, stepName์ธ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๊ณ ์์ผ๋ฉด ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํฉ๋๋ค.
- ์ฐธ๊ณ ๋ก execute ๋ฉ์๋์ contribution, context ์ด๋ ํ Execution๋ฅผ ์ฐธ์กฐํ๋ ์๊ด์ด ์์ต๋๋ค.
- https://stackoverflow.com/questions/61828817/stepcontribution-or-chunkcontext-for-executioncontext-info
Spring Batch Job์ด ์คํ๋ ํ Tasklet1์ด ํธ์ถ๋ ๋น์์๋ ExecutionContext ์ ์ฅ์์ ์๋ฌด๋ฐ ๋ฐ์ดํฐ(key/value)๊ฐ ์กด์ฌํ์ง ์๊ธฐ ๋๋ฌธ์ jobExecutionContext, stepExecutionContext์ map์๋ ์๋ฌด๋ฐ ๊ฐ๋ ์กด์ฌํ์ง ์์ต๋๋ค.
(batch.taskletType, bacth.stepType์ ๊ฒฝ์ฐ ์คํ๋ ๋ ์ด๋ฏธ ์กด์ฌํ๋ ๊ฐ์ผ๋ก ๋ค์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋ ๋ฐ์ดํฐ์ ํจ๊ป ์ถ๊ฐ๋ก ์ค๋ช ๋๋ฆฌ๊ฒ ์ต๋๋ค.)
์ดํ ์กฐ๊ฑด๋ฌธ์ ํตํด jobExecutionContext, stepExecutionContext์ 'jobName', 'stepName'๋ฅผ key๋ก ํ๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํฉ๋๋ค.
๋ฐ๋ผ์ ํด๋น Tasklet์ด ์ข ๋ฃ๋๋ฉด Job, Step์ ExecutionContext์๋ jobName, stepName์ key๋ก ๊ฐ์ง๋ ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋ฉ๋๋ค.
ExecutionContextTasklet2
- ExecutionContext๊ฐ Job, Step ๊ฐ ๋ฐ์ดํฐ ๊ณต์ ๊ฐ ๊ฐ๋ฅํ์ง ํ์ ํ๊ธฐ ์ํด Tasklet1์์ ์ ์ฅํ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ์ฌ ํ์ธํฉ๋๋ค.
ExecutionContext์ ๋ฐ์ดํฐ๋ฅผ ํ์ธํด ๋ณด๋ฉด jobExecutionContext์๋ ์ด์ Tasklet1์์ ์ ์ฅํ {jobName:executionContextJob} ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ๊ณ , stepExecutionContext์๋ ๊ธฐ์กด ๊ฐ ์ธ ์๋ฌด๋ฐ ๋ฐ์ดํฐ๋ ์กด์ฌํ์ง ์๋ ๊ฑธ ํ์ธํ ์ ์์ต๋๋ค.
์ฆ, JobExecution์ ExecutionContext ๋ด์ ๋ฐ์ดํฐ๋ค์ Step๋ค ์ฌ์ด์์๋ ๋ฐ์ดํฐ ๊ณต์ ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
ExecutionContextTasklet3
- JobExecution์ ExecutionContext์์ key๊ฐ name์ธ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ํ ์กด์ฌํ์ง ์์ผ๋ฉด user1์ด๋ผ๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ํ ์์ธ๋ฅผ ๋ฐ์์ํต๋๋ค.
๋ค์์ผ๋ก Tasklet3์์ JobExecution์ ExecutionContext์๋ key๊ฐ name์ธ ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ๊ธฐ ์๊ธฐ ๋๋ฌธ์ ์์ธ๋ฅผ ๋ฐ์์ํจ ํ Job์ ์ค์งํ๊ณ , ์ดํ Tasklet4๋ ์คํ์ด ๋์ง ์์ต๋๋ค.
ํ์ฌ๊น์ง ์คํ๋ Job & Step์ ๋ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฅผ ์ดํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๋ง์ง๋ง ์ฌ์ง์ธ BATCH_STEP_EXECUTION_CONTEXT์๋ ์์์ ์ดํด๋ณด์๋ map์ ๊ธฐ๋ณธ ๋ฐ์ดํฐ๋ฅผ ํฌํจํ์ฌ SHORT_CONTEXT ์ปฌ๋ผ์ ์ ์ฅ์ ํฉ๋๋ค.
์ ์ํ์์ Spring Batch๋ฅผ ๋ค์ ์คํํด๋ณด๋ฉด ์ด์ ๊ณผ๋ ๋ฌ๋ฆฌ Tasklet3์์ JobExecution์ ExecutionContext ์ ์ฅ์์ key๊ฐ name์ธ ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ๊ธฐ ๋๋ฌธ์ ์์ธ๊ฐ ๋ฐ์ํ์ง ์๊ณ ์คํจํ๋ step์ธ Tasklet3์ ์ํ๋์ง ์์๋ Tasklet4๊ฐ ์ ์์ ์ผ๋ก ์ํ๋ฉ๋๋ค.
ExecutionContextTasklet4
- JobExecution์ ExecutionContext ๋ด์ key๊ฐ name์ธ ๋ฐ์ดํฐ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
๐ ์ ๋ฆฌ
(์ฐธ๊ณ : ์ธํ๋ฐ Spring Batch)
์ ์ฌ์ง์ ํ ๋๋ก ์ ๋ฆฌํด ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- JobExecution์์ ์์ฑ๋๋ ExecutionContext
- ์๋ก ๋ค๋ฅธ Job์ ๋ฐ์ดํฐ ๊ณต์ ๋ถ๊ฐ๋ฅ
- ๋์ผํ Job ๋ด์์ Step ์ฌ์ด์์๋ ๊ณต์ ๊ฐ๋ฅ
- StepExecution์์ ์์ฑ๋๋ ExecutionContext
- Step ์ฌ์ด์์๋ ๊ณต์ ๊ฐ ๋ถ๊ฐ๋ฅ
์ฐธ๊ณ ๋ฌธ์
- https://docs.spring.io/spring-batch/docs/current/reference/html/index-single.html
- https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B0%B0%EC%B9%98/dashboard
'Spring > Spring Batch' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Spring Batch (8) JobLauncher (0) | 2022.11.11 |
---|---|
Spring Batch (7) JobRepository (0) | 2022.11.08 |
Spring Batch (5) Step, StepExecution (0) | 2022.11.03 |
Spring Batch (4) Job, JobInstance, JobParameters, JobExecution (0) | 2022.11.01 |
Spring Batch (3) DB ์คํค๋ง (0) | 2022.10.30 |
๋๊ธ