【Quartz】配置最简单的集群

时间:2023-05-28 22:22:02

  在许多情况,我们希望我们的定时任务是可靠的,不会因系统故障、机器宕机而导致某一笔定时任务不能按时运行。这种情况下,我们就需要为Quartz做个集群。

  最简单的情况,有两台机器或两个应用,同时维护一批定时任务,假如其中一个机器或应用出现问题,还有另外一个应用保底使用。

  代码与上一节【Quartz】将定时任务持久化到数据库基本一致,只列出不同的代码。

  在quartz.properties配置中设置需要集群,而集群节点的ID则由quartz自动生成

org.quartz.jobStore.isClustered = true
org.quartz.scheduler.instanceId = AUTO

  汇总后为

【Quartz】配置最简单的集群
org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.dataSource = myDS
# Cluster
org.quartz.jobStore.isClustered = true
org.quartz.scheduler.instanceId = AUTO org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/ll?characterEncoding=utf-8
org.quartz.dataSource.myDS.user = root
org.quartz.dataSource.myDS.password = 123456
org.quartz.dataSource.myDS.maxConnections = 5
【Quartz】配置最简单的集群

  注:俩应用的配置应相似,除了某些特殊配置,如线程池数量、实例ID

  这里启动两个应用,其中一个应用需要注册定时任务(这里注册的定时任务每30秒运行一次);另外一个应用因集群关系则无需注册定时任务。所以,启动类有所区别。

  应用A的Bootstrap类

 package No01简单的定时任务;

 import java.util.concurrent.TimeUnit;

 import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class Bootstrap {
private static Logger logger = LoggerFactory.getLogger(Bootstrap.class); public static void main(String[] args) { try {
// 获取Scheduler实例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start(); // 具体任务
JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build(); // 触发时间点
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0,30 * * * * ? *");
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
.withSchedule(cronScheduleBuilder).build(); // 交由Scheduler安排触发
scheduler.scheduleJob(job, trigger); try {
TimeUnit.MINUTES.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
} // 关闭Scheduler
scheduler.shutdown(); } catch (SchedulerException se) {
logger.error(se.getMessage(), se);
}
} }

  应用B的Bootstrap类

 package No01简单的定时任务;

 import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class Bootstrap {
private static Logger logger = LoggerFactory.getLogger(Bootstrap.class); public static void main(String[] args) { try {
// 获取Scheduler实例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start(); } catch (SchedulerException se) {
logger.error(se.getMessage(), se);
}
} }

  现在,运行观察是否成功。先后启动应用A和应用B,运行并观察一段时间后,关闭应用A,继续观察。

  通过日志观察可见,首先定时任务有应用A执行,在应用A被关闭后,定时任务由应用B继续触发执行。

  注:这里观察到,似乎不是负载均衡,因为在应用A关闭后应用B才有机会运行。而我们理想中,应该是应用A与应用B互相补充、交替运行。这里主要因为只用了一个任务(只有一个触发器)做测试,如果运用多个触发器设置多个任务做测试,应用A与应用B互相补充、交替运行。