스프링 정리

Spring Batch - @PersistJobDataAfterExecution

void_melody 2023. 4. 4. 10:53

이전 포스팅에서 Job의 작업 실행횟수를 실행하기 위해 jobDataMap의 executeCount 변수를 활용한 적이 있다.

@Component
public class QuartzBatchJob implements org.quartz.Job {
    @Autowired
    private JobLauncher jobLauncher;
    @Autowired
    private BeanUtil beanUtil;

    private int executeCount = 0;

    @SneakyThrows
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDetail jobDetail = context.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        if(jobDataMap.containsKey("executeCount")){
            executeCount = jobDataMap.getInt("executeCount");
        }
        jobDataMap.put("executeCount", ++executeCount);

        Job job = (Job) beanUtil.getBean((String) jobDataMap.get(QuartzService.JOB_NAME));

        JobParameters jobParameters = new JobParametersBuilder()
                .addDate("curDate", new Date())
                .toJobParameters();

        jobLauncher.run(job,jobParameters);
    }
}

JobExcutionContext가 무엇일까? 아니 그 전에 JobExcution은 무엇일까?

 

JobLauncher를 통해 배치 잡이 실행된다.

배치 잡이 실행되면 JobInstance가 생성된다.

 

JobInstance는 잡의 논리적 실행을 나타낸다. Job의 이름, Job에게 전달되어 실행시에 사용되는 식별 파라미터

해당 두 가지로 식별된다.

 

JobExecution은 무엇일까?

잡 실행의 실제 시도를 의미한다. 잡이 처음부터 끝까지 단번에 실행 완료되었다면 JobInstance와 JobExecution은 단 하나씩만 존재할 것이다.

첫 번째 Job 실행 후 오류 상태로 종료가 되었다면, 이전과 동일한 파라미터로 해당 JobInstance를 실행하려고 시도할 때마다 새로운 JobExecution이 생성된다.

 

JobExecutionContext는 하나의 Job에 해당하는 Context이다. 그렇기에 Job을 구성하는 step들 간에는 공유가 가능하다.

 

그렇다면, 현재 나는 Job이 딱 한번만 실행하길 원하는 상황이었다.

그런데 execute를 통해 호출이 끝나면 그 Job은 그냥 끝난 것이다.

다시 호출이 되면 다시 시작하는 것이니 다시 또 executeCount가 초기값으로 시작될 것이다.

 

해당 문제를 고민하다가 찾은 결과는 생각보다 허무했다.

그냥 말 그대로 해당 executeCount, 더 나아가 Job이 끝나도 해당 정보가 저장되게 하면 되는 것이었다.(stateful?)

@PersistJobDataAfterExecution을 붙여줌으로써, 해당 문제를 해결했다.

@PersistJobDataAfterExecution // jobDataMap 데이터 수정 이후 다음 실행에도 데이터 반영
@Component
public class QuartzBatchJob implements org.quartz.Job {
    @Autowired
    private JobLauncher jobLauncher;
    @Autowired
    private BeanUtil beanUtil;

    private int executeCount = 0;

    @SneakyThrows
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDetail jobDetail = context.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        if(jobDataMap.containsKey("executeCount")){
            executeCount = jobDataMap.getInt("executeCount");
        }
        jobDataMap.put("executeCount", ++executeCount);

        Job job = (Job) beanUtil.getBean((String) jobDataMap.get(QuartzService.JOB_NAME));

        JobParameters jobParameters = new JobParametersBuilder()
                .addDate("curDate", new Date())
                .toJobParameters();

        jobLauncher.run(job,jobParameters);
    }
}