복붙노트

[SPRING] Quartz 트리거를 데이터베이스에 유지하는 올바른 방법

SPRING

Quartz 트리거를 데이터베이스에 유지하는 올바른 방법

저는 Quartz를 처음 접했고 Spring 웹 애플리케이션에서 일부 작업을 스케줄해야합니다.

저는 Spring + Quartz 통합에 대해 알고 있습니다. (Spring v 3.1.1을 사용하고 있습니다.) 이것이 올바른 방법인지 궁금합니다.

특히 응용 프로그램을 다시 시작할 때 다시 초기화 할 수 있도록 예약 된 작업을 DB에 유지해야합니다.

Spring 스케쥴링 래퍼가 제공하는 유틸리티가 있습니까? 따라야 할 "잘 알려진"접근 방식을 제안 해 주시겠습니까?

해결법

  1. ==============================

    1.이 시나리오를 처리하는 한 가지 방법이 있습니다.

    이 시나리오를 처리하는 한 가지 방법이 있습니다.

    먼저 Spring Configuration에서 SchedulerFactoryBean을 지정하여 다른 Bean에 Scheduler를 삽입 할 수 있습니다.

    <bean name="SchedulerFactory"
        class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="applicationContextSchedulerContextKey">
            <value>applicationContext</value>
        </property>
    </bean>
    

    그런 다음 응용 프로그램에서 작업을 만들 때 작업의 세부 정보를 데이터베이스에 저장합니다. 이 서비스는 내 컨트롤러 중 하나에 의해 호출되며 작업을 예약합니다.

    @Component
    public class FollowJobService {
    
        @Autowired
        private FollowJobRepository followJobRepository;
    
        @Autowired
        Scheduler scheduler;
    
        @Autowired
        ListableBeanFactory beanFactory;
    
        @Autowired
        JobSchedulerLocator locator;
    
        public FollowJob findByClient(Client client){
            return followJobRepository.findByClient(client);
        }
    
        public void saveAndSchedule(FollowJob job) {
            job.setJobType(JobType.FOLLOW_JOB);
            job.setCreatedDt(new Date());
            job.setIsEnabled(true);
            job.setIsCompleted(false);
    
            JobContext context = new JobContext(beanFactory, scheduler, locator, job);
            job.setQuartzGroup(context.getQuartzGroup());
            job.setQuartzName(context.getQuartzName());
    
            followJobRepository.save(job);
    
            JobSchedulerUtil.schedule(new JobContext(beanFactory, scheduler, locator, job));
        }
    }
    

    빌드 한 JobContext에는 작업에 대한 세부 정보가 포함되어 있으며 결국 작업 예약을위한 유틸리티로 전달됩니다. 다음은 작업을 실제로 스케쥴하는 유틸리티 메소드의 코드입니다. 내 서비스에서 JobScheduler를 autowire하고 JobContext에 전달합니다. 또한 저장소를 사용하여 데이터베이스에 작업을 저장합니다.

    /**
     * Schedules a DATA_MINING_JOB for the client. The job will attempt to enter
     * followers of the target into the database.
     */
    @Override
    public void schedule(JobContext context) {
        Client client = context.getNetworkSociallyJob().getClient();
        this.logScheduleAttempt(context, client);
    
        JobDetail jobDetails = JobBuilder.newJob(this.getJobClass()).withIdentity(context.getQuartzName(), context.getQuartzGroup()).build();
        jobDetails.getJobDataMap().put("job", context.getNetworkSociallyJob());
        jobDetails.getJobDataMap().put("repositories", context.getRepositories());
    
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(context.getQuartzName() + "-trigger", context.getQuartzGroup())
                .withSchedule(cronSchedule(this.getSchedule())).build();
    
        try {
            context.getScheduler().scheduleJob(jobDetails, trigger);            
            this.logSuccess(context, client);
    
        } catch (SchedulerException e) {
            this.logFailure(context, client);
            e.printStackTrace();
        }
    }
    

    따라서이 코드가 모두 실행 된 후에 두 가지 일이 발생했습니다. 내 작업은 데이터베이스에 저장되며 쿼츠 스케줄러를 사용하여 예약되었습니다. 이제 응용 프로그램이 다시 시작되면 스케줄러로 작업을 다시 예약하려고합니다. 이를 위해 컨테이너가 다시 시작되거나 시작될 때마다 Spring에 의해 호출되는 ApplicationListener 를 구현하는 bean을 등록합니다.

    <bean id="jobInitializer" class="com.network.socially.web.jobs.JobInitializer"/>
    

    JobInitializer.class

    public class JobInitializer implements ApplicationListener<ContextRefreshedEvent> {
    
        Logger logger = LoggerFactory.getLogger(JobInitializer.class);
    
        @Autowired
        DataMiningJobRepository repository;
    
        @Autowired
        ApplicationJobRepository jobRepository;
    
        @Autowired
        Scheduler scheduler;
    
        @Autowired
        JobSchedulerLocator locator;
    
        @Autowired
        ListableBeanFactory beanFactory;
    
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            logger.info("Job Initilizer started.");
    
            //TODO: Modify this call to only pull completed & enabled jobs
            for (ApplicationJob applicationJob : jobRepository.findAll()) {
                if (applicationJob.getIsEnabled() && (applicationJob.getIsCompleted() == null || !applicationJob.getIsCompleted())) {
                    JobSchedulerUtil.schedule(new JobContext(beanFactory, scheduler, locator, applicationJob));
                }
            }       
        }
    
    }
    

    이 클래스는 ApplicationJob 인터페이스를 구현하는 각 작업의 인스턴스를 잡는 스케줄러와 저장소를 autowires합니다. 이러한 데이터베이스 레코드의 정보를 사용하여 스케줄러 유틸리티를 사용하여 작업을 재구성 할 수 있습니다.

    그래서 기본적으로 수동으로 데이터베이스에 작업을 저장하고 스케줄러의 인스턴스를 적절한 bean에 삽입하여 수동으로 스케줄링합니다. 다시 일정을 잡으려면 데이터베이스에 쿼리 한 다음 ApplicationListener를 사용하여 컨테이너의 다시 시작 및 시작을 고려하여 일정을 예약합니다.

  2. ==============================

    2.Spring과 Quartz JDBC 작업 저장소 통합에 사용할 수있는 문서가 꽤 있다고 가정합니다. 예를 들면 :

    Spring과 Quartz JDBC 작업 저장소 통합에 사용할 수있는 문서가 꽤 있다고 가정합니다. 예를 들면 :

  3. from https://stackoverflow.com/questions/17402112/correct-way-to-persist-quartz-triggers-in-database by cc-by-sa and MIT license