๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring/Spring Batch

Spring Batch (6) ExecutionContext

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

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

 

 

 

์ฐธ๊ณ  ๋ฌธ์„œ

 

๋ฐ˜์‘ํ˜•

'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

๋Œ“๊ธ€