ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스프링 배치 도메인 이해 -JobInstance
    Study/Spring Batch 2024. 1. 30. 06:14

    JobInstance

    기본 개념

    • Job이 실행될 때 구성되는 Job의 논리적 실행 단위로서 고유하게 식별 가능한 작업 실행을 나타낸다.
    • Job의 설정과 구성은 동일하지만 Job이 실행되는 시점에 처리하는 내용은 다르기 때문에 Job의 실행을 구분해야 한다.
      • 예) 하루에 한 번씩 배치 Job이 실행된다면 매일 실행되는 각각의 Job을 JobInstance로 표현.
    • JobInstance 생성 및 실행
      • 처음 시작하는 Job + JobParameter일 경우 새로운 JobInstance 생성
      • 이전과 동일한 Job + JobParameter으로 실행할 경우 이미 존재하는 JobInstance 리턴
        • 내부적으로 JobName + JobKey (JobParameter의 해시값)으로 JobInstance 객체를 얻는다. (from DB)
        • 더 이상 Job이 실행되지 않고 예외를 발생하게 된다.
    • Job과 1:N 관계

     

    BATCH_JOB_INSTANCE 테이블과 매핑

    JOB_NAME(Job)과 JOB_KEY(JobParameter 해시값)가 동일한 데이터는 중복해서 저장할 수 없다.

    출처 : 인프런 정수원 강의

    같은 JOB_NAME과 JOB_KEY로 실행이 불가능한 것을 확인하는 테스트를 해보자.

    빌드시 Job이 자동 실행되는 것을 막기 위해 다음과 같은 설정을 추가한다.

    spring.batch.job.enable의 기본 값이 true인데 이것을 false로 설정.

    spring:
      config:
        activate:
          on-profile: mysql
      datasource:
        hikari:
          jdbc-url: jdbc:mysql://localhost:3306/springbatch?useUnicode=true&characterEncoding=utf8
          username: root
          password: pass
          driver-class-name: com.mysql.jdbc.Driver
      batch:
        jdbc:
          initialize-schema: always
        job:
          enabled: false # 자동 실행을 막는다.

    ApplicationRunner를 상속받는 JobParameterTest 클래스를 만든다.

    @Component
    public class JobParameterTest implements ApplicationRunner { // 테스트를 하기 위해 수동으로 구성
    
        @Autowired
        JobLauncher jobLauncher; // Job을 실행시키는 JobLauncher class
    
        @Autowired
        Job job;
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
    
            JobParameters jobParameters = new JobParametersBuilder()
                    .addString("name", "user1")
                    .addLong("seq", 1L)
                    .toJobParameters();
    
            jobLauncher.run(job, jobParameters);
        }
    }

    JobParamters를 생성하면서 "name"과 "seq"를 지정 후 처음으로 Build하면 실행 성공.

    BATCH_JOB_INSTANCE 테이블에 Job이름과 JOB_KEY 한 줄이 추가로 쌓였다.

     

    BATCH_JOB_EXECUTION_PARAMS 테이블을 조회해보면 위에서 설정해준 name과 seq가 저장되어 있다.

    이 상태에서 한 번 더 실행해보면 JobInstanceAlreadyCompleteException 에러가 발생한다. 

    java.lang.IllegalStateException: Failed to execute ApplicationRunner
    	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:785) ~[spring-boot-2.5.1.jar:2.5.1]
    	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:772) ~[spring-boot-2.5.1.jar:2.5.1]
    	at org.springframework.boot.SpringApplication.run(SpringApplication.java:345) ~[spring-boot-2.5.1.jar:2.5.1]
    	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-2.5.1.jar:2.5.1]
    	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) ~[spring-boot-2.5.1.jar:2.5.1]
    	at io.springbatch.springbatchlecture.SpringBatchLectureApplication.main(SpringBatchLectureApplication.java:12) ~[classes/:na]
    Caused by: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={name=user1, seq=1}.  If you want to run this job again, change the parameters.
    	at org.springframework.batch.core.repository.support.SimpleJobRepository.createJobExecution(SimpleJobRepository.java:139) ~[spring-batch-core-4.3.3.jar:4.3.3]
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    	at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]

     

    A job instance already exists and is complete for parameters={name=user1, seq=1}.  If you want to run this job again, change the parameters.

     

    댓글

Designed by Tistory.