1. JobRepository, JobExplorer, JobOperation 의 역할

- JobRepository : meta-data 에 대한 CRUD

- JobExplorer : meta-data 에 대한 read-only 기능

- JobOperation : stop, restart 등 job 에 대한 제어

 

2. jobOperator 의 stop(jobExecutionId) 메소드

- 실행중인 job 을 stop 시킨다.

- Stop 은 graceful 하게 동작한다. (Stop이 즉시 이뤄지지 않으며 현재 실행중이던 step 은 끝까지 다 실행 된 후 job이 stop 된다)

 

3.  jobOperator 의 stop(jobExecutionId) 메소드 들여다 보기

(spring-batch-core-4.2.1 org.springframework.batch.core.launch.support.SimpleJobOperator.stop())

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
@Override
@Transactional
public boolean stop(long executionId) throws NoSuchJobExecutionException, JobExecutionNotRunningException {
  JobExecution jobExecution = findExecutionById(executionId);
  // Indicate the execution should be stopped by setting it's status to
  // 'STOPPING'. It is assumed that
  // the step implementation will check this status at chunk boundaries.
  BatchStatus status = jobExecution.getStatus();
  if (!(status == BatchStatus.STARTED || status == BatchStatus.STARTING)) {
     throw new JobExecutionNotRunningException("JobExecution must be running so that it can be stopped: "+jobExecution);
  }
  jobExecution.setStatus(BatchStatus.STOPPING);
  jobRepository.update(jobExecution);
  
  try {
     Job job = jobRegistry.getJob(jobExecution.getJobInstance().getJobName());
     
     if (job instanceof StepLocator) {//can only process as StepLocator is the only way to get the step object
        //get the current stepExecution
        for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
           logger.info("STOP 메소드 내의 jobExecutionId : "  + stepExecution.getJobExecutionId());
           
           if (stepExecution.getStatus().isRunning()) {
              try {
                 //have the step execution that's running -> need to 'stop' it
                 Step step = ((StepLocator)job).getStep(stepExecution.getStepName());
                 if (step instanceof TaskletStep) {
                    Tasklet tasklet = ((TaskletStep)step).getTasklet();
                    if (tasklet instanceof StoppableTasklet) {
                       StepSynchronizationManager.register(stepExecution);
                       logger.info("stop stoppableTasklet ! ");
                       ((StoppableTasklet)tasklet).stop();
                       StepSynchronizationManager.release();
                    }
                 }
              }
              catch (NoSuchStepException e) {
                 logger.warn("Step not found",e);
              }
           }
        }
     }
  }
  catch (NoSuchJobException e) {
     logger.warn("Cannot find Job object in the job registry. StoppableTasklet#stop() will not be called",e);
  }
  
  return true;
}
cs

- StoppableTasklet 의 stop() 을 호출하고 있음을 알 수 있다.

- StoppableTasklet 은 Tasklet interface를 상속받는 interface이며 내부적으로 stop() 추상메소드를 갖고있다.

- batch job 에서 Tasklet 대신 StopTasklet 을 구현한 후 stop() 메소드를 오버라이딩 할 경우, jobOperator.stop() 호출시에 batch job 내의 flag 값 제어 등을 할 수 있다. 마치 리스너와 같이 동작한다.

 

 

4. stop 호출에 따른 meta-data 의 STATUS 필드 값 변화 순서

1. jobOperator.stop(jobExecutionId); 호출

2. step의 STATUS필드값이 stopped 로 바뀜 (step_execution 테이블의 status 필드값)

3. job 의 STATUS필드값이 stopping 으로 바뀜 (job_execution 테이블의 status 필드값)

4. 스텝이 끝난 후 job의 status를 stopped 로 바꿈

 

 

https://docs.spring.io/spring-batch/docs/current/reference/html/step.html

 

반응형

+ Recent posts