스케쥴러 구현

023·2024년 7월 11일
0
post-thumbnail

서론

영화 데이터 접근 방식의 변화를 가져온 네이버 영화 API의 서비스 종료에 대응하기 위해, CGV 웹사이트에서 직접 데이터를 크롤링하는 방안이 필요하게 되었다. 이 글에서는 데이터 수집을 목표로, Quartz 스케줄링 라이브러리를 사용하여 특정 시각에 자동화된 크롤링을 실행하는 시스템을 구축하고자 한다.

1. 기술 구현 상세

  1. Quartz 라이브러리 통합

    • Maven과 Gradle을 통해 프로젝트에 Quartz 라이브러리를 추가함으로써, 스케줄링 기능을 활성화한다.
  2. 스케줄러 구성 및 초기화

    • Quartz 스케줄러는 StdSchedulerFactory를 통해 인스턴스화되며, 스케줄러의 기본 설정을 로드하여 작업 스케줄링 환경을 구축한다. 스케줄러는 시스템의 중앙에서 모든 작업을 관리하며, 정해진 시간에 작업을 실행한다.
  3. Job 클래스의 구현

    • Quartz의 Job 인터페이스를 구현하여 MyJob 클래스를 정의한다. 이 클래스 내에서는 실제 크롤링 로직이 포함되어 있으며, execute 메소드는 스케줄된 시간에 자동으로 호출된다. 이 메소드는 CGV 웹사이트에 접근하여 필요한 영화 데이터를 추출하고 처리하는 역할을 한다.
  4. 트리거 설정 및 작업 등록

    • 작업 실행의 정확한 시간과 주기를 정의하기 위해 크론 표현식을 사용한 크론 트리거를 설정한다. 이 트리거는 작업이 매일 자정에 실행되도록 구성되며, 스케줄러에 작업과 함께 등록된다. 주로 SimpleTriggerCronTrigger를 사용한다.
  5. 작업 실행 및 모니터링

    • 스케줄러가 활성화되면, 정의된 트리거에 의해 MyJobexecute 메소드가 호출된다. 크롤링 로직이 실행되며, 실행 과정 중 발생할 수 있는 예외를 적절히 처리하고, 실행 상태와 결과를 로깅한다.

2. 구현

1. Maven 의존성 추가

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>

2. 스케줄러 설정 및 시작

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

public class QuartzSchedulerExample {
    public static void main(String[] args) {
        try {
            // 스케줄러 팩토리에서 스케줄러 가져오기
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

            // 스케줄러 시작
            scheduler.start();

            // JobDetail 생성
            JobDetail job = JobBuilder.newJob(MyJob.class)
                    .withIdentity("myJob", "group1")
                    .build();

            // Trigger 생성 (매일 자정에 실행)
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("myTrigger", "group1")
                    .withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(0, 0))
                    .build();

            // JobDetail과 Trigger를 스케줄러에 등록
            scheduler.scheduleJob(job, trigger);

        } catch (SchedulerException se) {
            se.printStackTrace();
        }
    }
}

3. Job 클래스 작성

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 크롤링 작업 로직 구현
        System.out.println("Executing job at " + context.getFireTime());
        
        // 예: 크롤링 및 데이터 저장 로직
        crawlAndSaveMovies();
    }

    private void crawlAndSaveMovies() {
        // 크롤링 및 DB 저장 로직 구현
        System.out.println("Crawling and saving movies...");
    }
}

4. 다양한 Trigger 설정

  • 간단한 반복 트리거 (SimpleTrigger):

    Trigger trigger = TriggerBuilder.newTrigger()
            .withIdentity("simpleTrigger", "group1")
            .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                    .withIntervalInSeconds(10) // 10초마다 실행
                    .repeatForever())
            .build();
  • 크론 트리거 (CronTrigger):

    Trigger trigger = TriggerBuilder.newTrigger()
            .withIdentity("cronTrigger", "group1")
            .withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 * * ?")) // 매일 자정에 실행
            .build();

5. JobListener 및 TriggerListener 사용

Quartz는 작업 및 트리거의 상태를 모니터링하기 위해 리스너를 제공한다. 예를 들어, 작업이 시작되거나 완료될 때 특정 작업을 수행할 수 있다.

  • JobListener 구현:

    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.quartz.listeners.JobListenerSupport;
    
    public class MyJobListener extends JobListenerSupport {
        @Override
        public String getName() {
            return "MyJobListener";
        }
    
        @Override
        public void jobToBeExecuted(JobExecutionContext context) {
            System.out.println("Job is about to be executed: " + context.getJobDetail().getKey());
        }
    
        @Override
        public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
            System.out.println("Job was executed: " + context.getJobDetail().getKey());
        }
    }
  • 리스너 등록:

    Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
    scheduler.getListenerManager().addJobListener(new MyJobListener());

6. JobStore 설정 (Optional)

Quartz는 작업 및 트리거 정보를 저장하는 방법을 정의하는 여러 JobStore를 제공한다. 기본적으로 RAMJobStore가 사용되지만, 영구 저장을 위해 JDBCJobStore를 사용할 수 있다.

  • Quartz 프로퍼티 설정 (quartz.properties):

    org.quartz.scheduler.instanceName = MyScheduler
    org.quartz.scheduler.instanceId = AUTO
    
    org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
    org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    org.quartz.jobStore.dataSource = myDS
    org.quartz.jobStore.tablePrefix = QRTZ_
    
    org.quartz.dataSource.myDS.driver = com.mysql.cj.jdbc.Driver
    org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz
    org.quartz.dataSource.myDS.user = quartz
    org.quartz.dataSource.myDS.password = password
    org.quartz.dataSource.myDS.maxConnections = 5
  • 데이터베이스 스키마 설정: Quartz가 사용할 테이블을 데이터베이스에 생성한다. Quartz의 스키마 파일을 사용하여 테이블을 생성할 수 있다.

3. 요약

  1. Quartz 라이브러리 추가: Maven 또는 Gradle을 사용하여 프로젝트에 Quartz 의존성을 추가한다.
  2. 스케줄러 설정 및 시작: StdSchedulerFactory를 사용하여 스케줄러를 설정하고 시작한다.
  3. Job 클래스 작성: Job 인터페이스를 구현하여 작업을 정의한다.
  4. Trigger 설정: SimpleTrigger 또는 CronTrigger를 사용하여 작업 실행 주기를 설정한다.
  5. 리스너 사용: JobListenerTriggerListener를 사용하여 작업 및 트리거 상태를 모니터링한다.
  6. JobStore 설정: 필요에 따라 작업 및 트리거 정보를 영구적으로 저장하기 위해 JobStore를 설정한다.

이와 같은 방식으로 Quartz를 사용하여 다양한 스케줄링 요구 사항을 충족할 수 있다. 필요에 따라 트리거를 조정하고, Job 클래스의 로직을 수정하여 다양한 작업을 수행할 수 있다.

결론

이 프로젝트를 통해 구축된 자동화된 크롤링 시스템은 데이터의 신뢰성을 보장하고, 데이터 접근성을 대폭 향상시켰다. 또한, Quartz 스케줄러의 정밀한 작업 관리 기능은 작업 실행의 정확성을 보장하며, 다양한 작업 스케줄링 요구 사항에 유연하게 대응할 수 있도록 한다. 향후 이 시스템은 추가적인 데이터 소스 통합과 더욱 복잡한 스케줄링 요구 사항에 대응하기 위해 지속적으로 개선될 예정이다.

profile
Get your hands dirty

0개의 댓글