头图

SpringBoot 如何配置 quartz 为分布式定时任务

首发于 Dale’s blog

背景

项目需要一个分布式的定时任务,预研之后选择使用 quartz
quartz 的分布式需要依赖关系型数据库支持存储一些任务信息。建表sql存在于 quartz 项目中,github 可见
库中提供了多种数据库的执行sql,我的项目采用的 postgres 作为持久化数据库。

配置 quartz

QuartzJobFactory

/**
 * quartz job factory
 *
 * @author Dale
 */
@Component
public 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
 */
@Configuration
public 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=liveScheduler
org.quartz.scheduler.instanceId=AUTO

org.quartz.jobStore.useProperties=true
org.quartz.jobStore.isClustered=true
# 由于使用 postgres,quartz 的表并不是建在 publish schema 下,所以需要在 tablePrefix 设置schema的名字
org.quartz.jobStore.tablePrefix=quartz.qrtz_
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate

使用

先定义一个 job

@Repository
public 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);
    }

Dale
103 声望3 粉丝

谁敢横刀立马!