quartz job同表不同环境

本文探讨了在开发、测试及生产环境中,Quartz定时任务因集群模式导致的任务错配问题。介绍了两种解决方案:一是通过建立不同环境的独立表并调整quartz.properties;二是设置不同的Scheduler实例名,通过schedulerName区分,避免任务跨环境执行。同时,提供了具体的配置示例与代码改造细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先声明下,下面的讨论纯属技术讨论,由于操作代价比较大,实际意义并不大。
我们的开发一般分为开发环境,测试环境和生产环境。由于机器资源限制,开发环境和测试环境虽然部署着不同的应用,但是数据库都是同一个库。一般情况下,是可以这样玩的,也不会有什么问题。但是定时任务经常会出现开发环境启动的任务跑在了测试环境上,然后日志在开发环境里就查不到了。出现这种情况是因为在quartz.properties文件中,我们开启了集群模式:

org.quartz.jobStore.isClustered: true

这样一来,定时任务触发时,基本会随机选择一个节点运行这个任务。如何避免这样的情况呢?

一种方案是,不同的环境建不同的表,然后不同的环境使用不同的quartz.properties,更改表前缀:

org.quartz.jobStore.tablePrefix: MY_QRTZ_

这种方案比较简单,有个缺点就是要新建单独的一套表,本质上我们可以理解为还是使用了不同的库。

第二种方案是,不同的环境,使用不同的scheduler实例,并通过shcedulerName区分。Quartz中的所有表ched_name都是联合主键之一,不同的scheduler实例是不会相互影响的,这样属于开发环境的实例的定时任务就不会跑到测试环境中去。下面我们就来演示如何改造。

1、修改quartz.properties文件

将quart.properties文件拷贝一份,命名为quartz.dev.properties,然后修改instanceName

org.quartz.scheduler.instanceName: quartzSchedulerDev

2、修改quartz配置

针对不同的环境设置读取相应的quartz.properties文件。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

	<!-- quartz scheduler配置 -->
	<beans profile="dve">
		<bean name="quartzScheduler" class="com.gameloft9.demo.jobs.MySchedulerFactoryBean">
			<property name="dataSource" ref="dataSource" />
			<property name="jobFactory" ref="springJobFactory"/>
			<property name="configLocation" value="classpath:quartz.dev.properties" />
			<property name="overwriteExistingJobs" value="true" />
			<property name="autoStartup" value="false" />
			<property name="exposeSchedulerInRepository" value="true" />
		</bean>
	</beans>

	<beans profile="!dev">
		<bean name="quartzScheduler" class="com.gameloft9.demo.jobs.MySchedulerFactoryBean">
			<property name="dataSource" ref="dataSource" />
			<property name="jobFactory" ref="springJobFactory"/>
			<property name="configLocation" value="classpath:quartz.properties" />
			<property name="overwriteExistingJobs" value="true" />
			<property name="autoStartup" value="false" />
			<property name="exposeSchedulerInRepository" value="true" />
		</bean>
	</beans>

</beans>

3、改造SchedulerFactoryBean

我们对SchedulerFactoryBean也需要做一点简单的改造。因为在SchedulerFactoryBean初始化Scheduler的时候,强行将上面配置的beanName覆盖了quartz.properties中的instanceName的值:

@Override
	public void setBeanName(String name) {
		if (this.schedulerName == null) {
			this.schedulerName = name;
		}
	}
private void initSchedulerFactory(SchedulerFactory schedulerFactory) throws SchedulerException, IOException {
		......
		// Make sure to set the scheduler name as configured in the Spring configuration.
		if (this.schedulerName != null) {
			mergedProps.put(StdSchedulerFactory.PROP_SCHED_INSTANCE_NAME, this.schedulerName);
		}

		......
	}

因此我们可以单独派生出一个类,然后将setBean重写,不要设置schdulerName即可。

package com.gameloft9.demo.jobs;

import org.springframework.scheduling.quartz.SchedulerFactoryBean;

/**
 * 自定义SchedulerFactoryBean
 * Created by gameloft9 on 2019/4/12.
 */
public class MySchedulerFactoryBean extends SchedulerFactoryBean {

    @Override
    public void setBeanName(String name) {
        // 避免配置的beanName覆盖了quartz.properties中的org.quartz.scheduler.instanceName
        return;
    }

}

这样创建的SchedulerInstance的名称就是我们quartz.properties中配置的了。到此改造就结束了。

数据库截图

在这里插入图片描述

注意

不管是方案一,还是方案二,由于我们只是定时任务从环境上区分了,业务逻辑还是使用的同一个底层数据库。因此定时任务的执行间隔需要巧妙的设置下,以保持和原来单个环境下的执行频率一致。例如某个定时任务原本是每条凌晨1点执行,那么在开发环境和测试环境下,我们的时间就要设置成1号开发环境执行,2号测试环境执行。意思就是避免到点后,开发环境和测试环境同时执行了。通过这样的设置,定时任务就还是每天执行一次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值