SpringBoot 如何配置 quartz 为分布式定时工作

首发于 Dale’s blog

背景

我的项目须要一个分布式的定时工作,预研之后抉择应用 quartz
quartz 的分布式须要依赖关系型数据库反对存储一些工作信息。建表sql存在于 quartz 我的项目中,github 可见
库中提供了多种数据库的执行sql,我的我的项目采纳的 postgres 作为长久化数据库。

配置 quartz

QuartzJobFactory

/** * quartz job factory * * @author Dale */@Componentpublic class QuartzJobFactory extends AdaptableJobFactory {    @Autowired    private AutowireCapableBeanFactory autowireCapableBeanFactory;    @Override    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {        Object jobInstance = super.createJobInstance(bundle);        autowireCapableBeanFactory.autowireBean(jobInstance);        return jobInstance;    }}

QuartzConf

/** * 配置分布式 quartz * * @author Dale */@Configurationpublic class QuartzConf {    private QuartzJobFactory quartzJobFactory;    @Resource(name = "master")    private DataSourceProperties masterProperties;    @Autowired    public void setQuartzJobFactory(QuartzJobFactory quartzJobFactory) {        this.quartzJobFactory = quartzJobFactory;    }    @Bean    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();        // 设置 quartz 的配置文件是 classpath 下的 quartz.properties 文件        propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties"));        propertiesFactoryBean.afterPropertiesSet();        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();        schedulerFactoryBean.setQuartzProperties(Objects.requireNonNull(propertiesFactoryBean.getObject()));        schedulerFactoryBean.setJobFactory(quartzJobFactory);        schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContextKey");        schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(true);        schedulerFactoryBean.setOverwriteExistingJobs(false);        schedulerFactoryBean.setStartupDelay(10);        // 设置 quartz 的DataSource 为主库的配置        schedulerFactoryBean.setDataSource(masterProperties.initializeDataSourceBuilder().type(DruidDataSource.class).build());        return schedulerFactoryBean;    }    @Bean(name = "scheduler")    public Scheduler scheduler() throws IOException {        return schedulerFactoryBean().getScheduler();    }}
留神:因为我的项目先前配置了数据库的主从拆散,所以专用数据库链接,防止额定再有一处数据库连贯配置。

quartz.properties

org.quartz.scheduler.instanceName=liveSchedulerorg.quartz.scheduler.instanceId=AUTOorg.quartz.jobStore.useProperties=trueorg.quartz.jobStore.isClustered=true# 因为应用 postgres,quartz 的表并不是建在 publish schema 下,所以须要在 tablePrefix 设置schema的名字org.quartz.jobStore.tablePrefix=quartz.qrtz_org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate

应用

先定义一个 job

@Repositorypublic class LotteryJobs implements Job {    @Override    public void execute(JobExecutionContext context) throws JobExecutionException {        // todo::    }}

而后调用

JobDetail jobDetail = JobBuilder.newJob(LotteryJobs.class).withIdentity("lottery-" + lotteryEntity.getId()).build();jobDetail.getJobDataMap().put("lotteryId","");jobDetail.getJobDataMap().put("roomId", "");Trigger trigger = TriggerBuilder.newTrigger().withIdentity("lottery-" + lotteryEntity.getId()).startAt(getLotteryTime()).build();try {scheduler.scheduleJob(jobDetail, trigger);    } catch (SchedulerException e) {        LOGGER.error("lottery schedule create error,lotteryId:" + lotteryEntity.getId(), e);        throw new BusinessException(ApiCode.ERROR);    }