博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring-boot-quartz, 依赖spring-boot-parent good
阅读量:6175 次
发布时间:2019-06-21

本文共 11529 字,大约阅读时间需要 38 分钟。

 

/**   *          state的值代表该任务触发器的状态:         STATE_BLOCKED   4 // 运行         STATE_COMPLETE  2  //完成那一刻,不过一般不用这个判断Job状态         STATE_ERROR     3  // 错误         STATE_NONE  -1      //未知         STATE_NORMAL    0   //正常无任务,用这个判断Job是否在运行         STATE_PAUSED    1   //暂停状态  */
import java.util.Date;    import org.quartz.CronTrigger;  import org.quartz.JobDetail;  import org.quartz.Scheduler;  import org.quartz.SchedulerException;  import org.quartz.SchedulerFactory;  import org.quartz.SimpleTrigger;  import org.quartz.Trigger;  import org.quartz.impl.StdScheduler;  import org.quartz.impl.StdSchedulerFactory;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory;  import org.springframework.context.ApplicationContext;  import org.springframework.scheduling.quartz.SchedulerFactoryBean;    import cn.wa8.qweb.extract.action.Extract2DB;  public class SimpleRun {        private static Logger log = LoggerFactory.getLogger(SimpleRun.class);        public void run() throws Exception {          SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();          Scheduler sched = schedFact.getScheduler();          JobDetail jobDetail = new JobDetail("myJob",null,SimpleJob.class);          SimpleTrigger trigger = new SimpleTrigger("myTrigger",                  null,                  new Date(),                  null,                  SimpleTrigger.REPEAT_INDEFINITELY,                  30L * 1000L);                    sched.scheduleJob(jobDetail, trigger);          //sched.addJobListener(new MyTriggerListener());          SimpleJob.preDate = new Date();          sched.start();          System.out.println("starting");   /**   *          state的值代表该任务触发器的状态:         STATE_BLOCKED   4 // 运行         STATE_COMPLETE  2  //完成那一刻,不过一般不用这个判断Job状态         STATE_ERROR     3  // 错误         STATE_NONE  -1      //未知         STATE_NORMAL    0   //正常无任务,用这个判断Job是否在运行         STATE_PAUSED    1   //暂停状态  */      while (true){          if(4 == sched.getTriggerState("myTrigger", null)){              System.out.println("running");          }else if(0 == sched.getTriggerState("myTrigger", null)){              System.out.println("ending");          }else {              System.out.println("error state:"+sched.getTriggerState("myTrigger", null));          }          try {              Thread.sleep(5*1000);          } catch (Exception e) {              // TODO: handle exception          }      }  }        public static void main(String[] args)  {                    SimpleRun simpleRun = new SimpleRun();                    try {              simpleRun.run();          } catch (Exception e) {              e.printStackTrace();          }      }  }

 

 

import java.util.Date;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory;    import cn.wa8.qweb.extract.action.Extract2DB;    import org.quartz.Job;  import org.quartz.JobExecutionContext;  import org.quartz.JobExecutionException;  import org.quartz.StatefulJob;  /*Extract2DB extract2db = new Extract2DB();     extract2db.CommonBaseExtract();*/    public class SimpleJob  implements StatefulJob{      public static Date preDate ;      public void execute(JobExecutionContext arg0) throws JobExecutionException {          System.out.println("into Job");          Date currentDate = new Date();          Long s = (currentDate.getTime()-preDate.getTime())/1000;          try {              Thread.sleep(10*1000);          } catch (Exception e) {              e.printStackTrace();          }          System.out.println(s);          System.out.println("leave Job:"+Thread.currentThread().toString());          preDate =currentDate;      }    }

http://blog.csdn.net/u010666884/article/details/51842610

都是执行时间大于间隔时间才会出现的情况,实际做了测试和http://blog.sina.com.cn/s/blog_56d8ea900100cecq.html第2点有点不符,记录如下:

第一种情况:misfire设置时间为600秒;任务每隔2分钟执行一次;任务执行时间为3分钟;上次执行时间    下次执行时间    状态        解释20:23:04        20:25:04        正在执行    任务实际要执行到20:26:04,推后两分钟是20:28:04

 

时间到了20:26:04。日志变更为:

20:25:04        20:27:04        正在执行    任务实际要执行的20:29:04,推后两分钟是20:31:04

 

时间到了20:29:04,日志变更为:

20:27:04        20:29:04

连续三次发现,实际开始的时间减去应该开始的时间差是递增的;上次执行和下次执行时间反映的实际情况都是不准确的,而且会出现下次执行时间小于当前时间的情况。

注意:持续执行的到 实际启动时间 减去 应该开始时间 大于等于misfire时间;奇怪的是,不是开始参考第二种情况继续执行,而是最后一次执行后即开始长时间等待,而且上次以及下次开始时间也不更新,保持原样;直到实际启动时间+misfire时间 时刻开始继续执行,并且更新上次以及下次开始时间,再开始一个上述周期。

第二种情况:misfire设置时间为6秒,任务每隔2分钟执行一次,任务执行时间为3分钟:

上次执行时间    下次执行时间    状态        解释18:08:12        18:10:12        正在执行    任务实际要执行到18:11:12,推后两分钟是18:13:12

 

时间到了18:11:12,日志变更为:

18:08:12        18:10:12        等待        超出misfire时间;任务还没有更新状态18:08:12        18:12:12        等待        是18:12:12,而不是18:13:12。

算法描述如下:

本次任务应该开始时间为18:10:12,应该结束时间为18:12:12;实际启动时间为18:11:12;实际启动后结束时间为18:13:12;实际启动时间减去应该开始时间超出了misfire,所以状态为等待,即本次任务不执行,从而上次执行时间不变;

计算下次执行时间:当前时间为18:11:12(或者一个稍微大于该值的值),拿应该结束时间以及实际启动后结束时间和当前时间比较,取当前时间往后的最小值作为下次任务启动时间。(算法兼容下面第2点说法)
18:12:12 18:14:12 正在执行
其他引用:
org.quartz.jobStore.misfireThreshold = 60000 #60秒 默认值
那么执行第一次作业是在10:01秒,这时会设定下一次的执行时间为10:02秒,要等一个作业执行完之后才有可用线程,大概要在10:11秒才能执行前面安排的应该在10:02执行的作业,这时就会用到misfireThreshold, 因为10:11与10:02之间的差值小于6000,所以执行该作业,并以10:02为基准设置下一次执行时间为10:03,这样造成每次实际执行时间与安排时间错位
如果 org.quartz.jobStore.misfireThreshold = 6000 #秒
同样,在10:11计划执行安排在10:02的作业,发现10:11与10:02之间的差值小于6000,那么直接跳过该作业,执行本应在当前时间执行的 作业,这时候会以10:11为基准设定下次作业执行时间为10:12(状态此段区间内一直是等待,只是更改了下次作业时间)

其他情况:

quartz有个全局的参数misfireThreshold设置可以允许的超时时间,超过了就不执行,未超过就执行。
比如设置了misfireThreshold=30分钟,如果一个任务定时在10:30执行,但在10:29服务器挂了,在10:50启动,虽然任务超时了21分钟,但小于misfireThreshold,所以还是可以执行
而如果服务器11:10才启动,那就misfire了。

对于周期性的任务,如果有misfire的情况出现,则会自动更新CronTrigger的时间周期

默认情况下会在当前时间马上执行前一个被misfire的任务
而如果设置MISFIRE_INSTRUCTION_DO_NOTHING,则不对misfire的任务做特殊处理,只从当前时间之后的下一次正常调度时间开始执行

http://blog.sina.com.cn/s/blog_56d8ea900101d2mh.html

 

http://www.quartz-scheduler.org/documentation/quartz-2.1.x/quick-start.html

spring-boot-quartz, 依赖spring-boot-parent

  • 项目启动后输入:http://localhost/
  • 数据库文件: 

application.properties

# IDENTITY (ContextIdApplicationContextInitializer)spring.application.index=WebQuartz.v1.1spring.application.name=WebQuartz#Serverserver.port=80server.jsp-servlet.class-name=org.apache.jasper.servlet.JspServletsecurity.basic.enabled=falsemanagement.security.enabled=false#MVCspring.mvc.view.prefix=/WEB-INF/views/spring.resources.static-locations=classpath:/static/security.basic.enabled=falsemanagement.security.enabled=false#LOGlogging.config=classpath:log4j2.xml

configuration

@Configurationpublic class QuartzConfig {    @Bean    public Scheduler scheduler() throws IOException, SchedulerException { SchedulerFactory schedulerFactory = new StdSchedulerFactory(quartzProperties()); Scheduler scheduler = schedulerFactory.getScheduler(); scheduler.start(); return scheduler; } /** * 设置quartz属性 * @throws IOException * 2016年10月8日下午2:39:05 */ public Properties quartzProperties() throws IOException { Properties prop = new Properties(); prop.put("quartz.scheduler.instanceName", "ServerScheduler"); prop.put("org.quartz.scheduler.instanceId", "AUTO"); prop.put("org.quartz.scheduler.skipUpdateCheck", "true"); prop.put("org.quartz.scheduler.instanceId", "NON_CLUSTERED"); prop.put("org.quartz.scheduler.jobFactory.class", "org.quartz.simpl.SimpleJobFactory"); prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX"); prop.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.StdJDBCDelegate"); prop.put("org.quartz.jobStore.dataSource", "quartzDataSource"); prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); prop.put("org.quartz.jobStore.isClustered", "true"); prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); prop.put("org.quartz.threadPool.threadCount", "5"); prop.put("org.quartz.dataSource.quartzDataSource.driver", "com.mysql.jdbc.Driver"); prop.put("org.quartz.dataSource.quartzDataSource.URL", "jdbc:mysql://localhost:3306/demo-schema"); prop.put("org.quartz.dataSource.quartzDataSource.user", "root"); prop.put("org.quartz.dataSource.quartzDataSource.password", "123456"); prop.put("org.quartz.dataSource.quartzDataSource.maxConnections", "10"); return prop; } }

JS

@Servicepublic class TaskServiceImpl {    private Logger logger = LogManager.getLogger(getClass()); @Autowired private Scheduler scheduler; /** * 所有任务列表 * 2016年10月9日上午11:16:59 */ public List
list(){ List
list = new ArrayList<>(); try { for(String groupJob: scheduler.getJobGroupNames()){ for(JobKey jobKey: scheduler.getJobKeys(GroupMatcher.
groupEquals(groupJob))){ List
triggers = scheduler.getTriggersOfJob(jobKey); for (Trigger trigger: triggers) { Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey()); JobDetail jobDetail = scheduler.getJobDetail(jobKey); String cronExpression = "", createTime = ""; if (trigger instanceof CronTrigger) { CronTrigger cronTrigger = (CronTrigger) trigger; cronExpression = cronTrigger.getCronExpression(); createTime = cronTrigger.getDescription(); } TaskInfo info = new TaskInfo(); info.setJobName(jobKey.getName()); info.setJobGroup(jobKey.getGroup()); info.setJobDescription(jobDetail.getDescription()); info.setJobStatus(triggerState.name()); info.setCronExpression(cronExpression); info.setCreateTime(createTime); list.add(info); } } } } catch (SchedulerException e) { e.printStackTrace(); } return list; } /** * 保存定时任务 * @param info * 2016年10月9日上午11:30:40 */ @SuppressWarnings("unchecked") public void addJob(TaskInfo info) { String jobName = info.getJobName(), jobGroup = info.getJobGroup(), cronExpression = info.getCronExpression(), jobDescription = info.getJobDescription(), createTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"); try { if (checkExists(jobName, jobGroup)) { logger.info("===> AddJob fail, job already exist, jobGroup:{}, jobName:{}", jobGroup, jobName); throw new ServiceException(String.format("Job已经存在, jobName:{%s},jobGroup:{%s}", jobName, jobGroup)); } TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); JobKey jobKey = JobKey.jobKey(jobName, jobGroup); CronScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing(); CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withDescription(createTime).withSchedule(schedBuilder).build(); Class
clazz = (Class
)Class.forName(jobName); JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(jobKey).withDescription(jobDescription).build(); scheduler.scheduleJob(jobDetail, trigger); } catch (SchedulerException | ClassNotFoundException e) { throw new ServiceException("类名不存在或执行表达式错误"); } } /** * 修改定时任务 * @param info * 2016年10月9日下午2:20:07 */ public void edit(TaskInfo info) { String jobName = info.getJobName(), jobGroup = info.getJobGroup(), cronExpression = info.getCronExpression(), jobDescription = info.getJobDescription(), createTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"); try { if (!checkExists(jobName, jobGroup)) { throw new ServiceException(String.format("Job不存在, jobName:{%s},jobGroup:{%s}", jobName, jobGroup)); } TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); JobKey jobKey = new JobKey(jobName, jobGroup); CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing(); CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withDescription(createTime).withSchedule(cronScheduleBuilder).build(); JobDetail jobDetail = scheduler.getJobDetail(jobKey); jobDetail.getJobBuilder().withDescription(jobDescription); HashSet
triggerSet
你可能感兴趣的文章
使用阿里云接口进行银行卡四要素实名认证
查看>>
聊聊excel生成图片的几种方式
查看>>
20 万网络节点背后的数据创新应用
查看>>
理论 | 朴素贝叶斯模型算法研究与实例分析
查看>>
docker安装gitlab只需要3分钟
查看>>
Android菜鸟学习js笔记 一
查看>>
Java基础之SPI机制
查看>>
使用js控制滚动条的位置
查看>>
【Tornado源码阅读笔记】tornado.web.Application
查看>>
lsyncd搭建测试
查看>>
移动web开发之像素和DPR
查看>>
nginx+tomcat+redis实现session共享
查看>>
UWP VirtualizedVariableSizedGridView 支持可虚拟化可变大小Item的View(二)
查看>>
rsync 介绍
查看>>
做一个合格的Team Leader -- 基本概念
查看>>
leetcode 190 Reverse Bits
查看>>
阿里巴巴发布AliOS品牌 重投汽车及IoT领域
查看>>
OPENCV图像处理(二):模糊
查看>>
glassfish4系统启动脚本
查看>>
VMware 虚拟化编程(13) — VMware 虚拟机的备份方案设计
查看>>