【Quartz】配置最简单的集群
在许多情况,我们希望我们的定时任务是可靠的,不会因系统故障、机器宕机而导致某一笔定时任务不能按时运行。这种情况下,我们就需要为Quartz做个集群。
最简单的情况,有两台机器或两个应用,同时维护一批定时任务,假如其中一个机器或应用出现问题,还有另外一个应用保底使用。
代码与上一节【Quartz】将定时任务持久化到数据库基本一致,只列出不同的代码。
在quartz.properties配置中设置需要集群,而集群节点的ID则由quartz自动生成
org.quartz.jobStore.isClustered = true org.quartz.scheduler.instanceId = AUTO
汇总后为
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
注:俩应用的配置应相似,除了某些特殊配置,如线程池数量、实例ID
这里启动两个应用,其中一个应用需要注册定时任务(这里注册的定时任务每30秒运行一次);另外一个应用因集群关系则无需注册定时任务。所以,启动类有所区别。
应用A的Bootstrap类
1 package No01简单的定时任务; 2 3 import java.util.concurrent.TimeUnit; 4 5 import org.quartz.CronScheduleBuilder; 6 import org.quartz.JobBuilder; 7 import org.quartz.JobDetail; 8 import org.quartz.Scheduler; 9 import org.quartz.SchedulerException; 10 import org.quartz.Trigger; 11 import org.quartz.TriggerBuilder; 12 import org.quartz.impl.StdSchedulerFactory; 13 import org.slf4j.Logger; 14 import org.slf4j.LoggerFactory; 15 16 17 public class Bootstrap { 18 private static Logger logger = LoggerFactory.getLogger(Bootstrap.class); 19 20 public static void main(String[] args) { 21 22 try { 23 // 获取Scheduler实例 24 Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); 25 scheduler.start(); 26 27 // 具体任务 28 JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build(); 29 30 // 触发时间点 31 CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0,30 * * * * ? *"); 32 Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1") 33 .withSchedule(cronScheduleBuilder).build(); 34 35 // 交由Scheduler安排触发 36 scheduler.scheduleJob(job, trigger); 37 38 try { 39 TimeUnit.MINUTES.sleep(3); 40 } catch (InterruptedException e) { 41 e.printStackTrace(); 42 } 43 44 // 关闭Scheduler 45 scheduler.shutdown(); 46 47 } catch (SchedulerException se) { 48 logger.error(se.getMessage(), se); 49 } 50 } 51 52 }
应用B的Bootstrap类
1 package No01简单的定时任务; 2 3 import org.quartz.Scheduler; 4 import org.quartz.SchedulerException; 5 import org.quartz.impl.StdSchedulerFactory; 6 import org.slf4j.Logger; 7 import org.slf4j.LoggerFactory; 8 9 10 public class Bootstrap { 11 private static Logger logger = LoggerFactory.getLogger(Bootstrap.class); 12 13 public static void main(String[] args) { 14 15 try { 16 // 获取Scheduler实例 17 Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); 18 scheduler.start(); 19 20 } catch (SchedulerException se) { 21 logger.error(se.getMessage(), se); 22 } 23 } 24 25 }
现在,运行观察是否成功。先后启动应用A和应用B,运行并观察一段时间后,关闭应用A,继续观察。
通过日志观察可见,首先定时任务有应用A执行,在应用A被关闭后,定时任务由应用B继续触发执行。
注:这里观察到,似乎不是负载均衡,因为在应用A关闭后应用B才有机会运行。而我们理想中,应该是应用A与应用B互相补充、交替运行。这里主要因为只用了一个任务(只有一个触发器)做测试,如果运用多个触发器设置多个任务做测试,应用A与应用B互相补充、交替运行。