Spring/Spring Batch

Spring Batch (6) ExecutionContext

์ฃผ๋ฐœ2 2022. 11. 5. 15:21
๋ฐ˜์‘ํ˜•

๐Ÿ“Ž 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

ExecutionContextTasklet1

Spring Batch Job์ด ์‹คํ–‰๋œ ํ›„ Tasklet1์ด ํ˜ธ์ถœ๋  ๋‹น์‹œ์—๋Š” ExecutionContext ์ €์žฅ์†Œ์— ์•„๋ฌด๋Ÿฐ ๋ฐ์ดํ„ฐ(key/value)๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— jobExecutionContext, stepExecutionContext์˜ map์—๋Š” ์•„๋ฌด๋Ÿฐ ๊ฐ’๋„ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

(batch.taskletType, bacth.stepType์˜ ๊ฒฝ์šฐ ์‹คํ–‰๋  ๋•Œ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ฐ’์œผ๋กœ ๋’ค์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ์™€ ํ•จ๊ป˜ ์ถ”๊ฐ€๋กœ ์„ค๋ช…๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.)

 

์ดํ›„ ์กฐ๊ฑด๋ฌธ์„ ํ†ตํ•ด jobExecutionContext, stepExecutionContext์— 'jobName', 'stepName'๋ฅผ key๋กœ ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

ExecutionContextTasklet1

๋”ฐ๋ผ์„œ ํ•ด๋‹น Tasklet์ด ์ข…๋ฃŒ๋˜๋ฉด Job, Step์˜ ExecutionContext์—๋Š” jobName, stepName์„ key๋กœ ๊ฐ€์ง€๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

 

 

 

ExecutionContextTasklet2

  • ExecutionContext๊ฐ€ Job, Step ๊ฐ„ ๋ฐ์ดํ„ฐ ๊ณต์œ ๊ฐ€ ๊ฐ€๋Šฅํ•œ์ง€ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•ด Tasklet1์—์„œ ์ €์žฅํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜์—ฌ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

ExecutionContextTasklet2

ExecutionContext์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธํ•ด ๋ณด๋ฉด jobExecutionContext์—๋Š” ์ด์ „ Tasklet1์—์„œ ์ €์žฅํ•œ {jobName:executionContextJob} ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•˜๊ณ , stepExecutionContext์—๋Š” ๊ธฐ์กด ๊ฐ’ ์™ธ ์•„๋ฌด๋Ÿฐ ๋ฐ์ดํ„ฐ๋„ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, JobExecution์˜ ExecutionContext ๋‚ด์˜ ๋ฐ์ดํ„ฐ๋“ค์€ Step๋“ค ์‚ฌ์ด์—์„œ๋Š” ๋ฐ์ดํ„ฐ ๊ณต์œ ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

 

 

 

ExecutionContextTasklet3

  • JobExecution์˜ ExecutionContext์—์„œ key๊ฐ€ name์ธ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•œ ํ›„ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด user1์ด๋ผ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•œ ํ›„ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

ExecutionContextTasklet3

๋‹ค์Œ์œผ๋กœ Tasklet3์—์„œ JobExecution์˜ ExecutionContext์—๋Š” key๊ฐ€ name์ธ ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•˜๊ธฐ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ ํ›„ Job์„ ์ค‘์ง€ํ•˜๊ณ , ์ดํ›„ Tasklet4๋Š” ์‹คํ–‰์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

ํ˜„์žฌ๊นŒ์ง€ ์‹คํ–‰๋œ Job & Step์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ดํŽด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

BATCH_JOB_EXECUTION
BATCH_JOB_EXECUTION_CONTEXT
BATCH_STEP_EXECUTION
BATCH_STEP_EXECUTION_CONTEXT

๋งˆ์ง€๋ง‰ ์‚ฌ์ง„์ธ 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 ์‚ฌ์ด์—์„œ๋„ ๊ณต์œ ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ

 

 

 

์ฐธ๊ณ  ๋ฌธ์„œ

 

๋ฐ˜์‘ํ˜•