NutzCN Logo
问答 Nutz的Quartz是否支持,动态设置运行的时间。
发布于 2227天前 作者 hcxxiaomo 1885 次浏览 复制 上一个帖子 下一个帖子
标签:

有一个功能需求就是,用户通过邮箱注册以后,要每隔一个星期就给该用户发一次课程对应的作业。由于每个用户的注册的时间不同,所以需要发送邮件的时间也不同。现在是已经配置了quartz.properties文件(注,这个配置里面的数据库信息,能不能使用db.propertie里面的数据库连接信息?)

org.quartz.scheduler.instanceName = NutzbookScheduler
#线程数量 执行调度最大的线程数
org.quartz.threadPool.threadCount = 5
#调度实例失效的检查时间间隔
org.quartz.jobStore.clusterCheckinInterval = 20000
#数据保存方式 持久化到数据库
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#数据库平台 mysql
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#表的前缀
org.quartz.jobStore.tablePrefix = QRTZ_
#数据库别名 spring配置数据源 则这里配置的数据源不起作用 在spring中指定quartz的数据源
org.quartz.jobStore.dataSource =qzDS
org.quartz.dataSource.qzDS.driver =com.mysql.jdbc.Driver
org.quartz.dataSource.qzDS.URL =jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8
org.quartz.dataSource.qzDS.user =root
org.quartz.dataSource.qzDS.password =123456
org.quartz.dataSource.qzDS.maxConnections =5

还有就是在MainSetup.java里面,已经通过 ioc.get(NutQuartzCronJobFactory.class); 注册了Quartz, 请问一下,能否直接通过ioc得到其维护的 protected Scheduler scheduler ,这样就可以scheduler.scheduleJob(jobDetail, trigger); 来增加定时任务。或者有其它的方式能实现动态设置时间的功能吗?请问要怎样实现。谢谢各位了!

7 回复

看QuatrzManager

非常感谢,刚看了 QuatrzManager ,大概写了代码,请问这样是不是就可以了?

@IocBean
@At("/quartz")
@Ok("json")
@Fail("http:500")
public class QuartzModule {
	
	@Inject
	private QuartzManager quartzManager;
	
	/**传入的Email和发送的时间*/
	public void add(String email ,String date){
		QuartzJob qj = new QuartzJob(jobKey, trigger, jobDetail);
		quartzManager.add(qj);
	}

}

jobKey, trigger, jobDetail 这三个参数的具体逻辑我自己实现就行了。

这个业务逻辑不应该是每天/每小时扫描一下数据库, 看看今天需要发送那些邮件, 然后发送吗? 还要上持久化....

前者更合理的样子

@lihongjie0209 是这样的,这个是一个在线的定时作业。就是abc@163.com用户注册之后,完成课程学习以后。会有 连续的几个星期的作业,而且时间必须是严格控制好的。而且每个人的学习周期是自己定的,所以每人都会不同的,所以不能做成定时任务。

发现一个nutz-integration-quartz的小问题,就不在github上面提了,在论坛写出来吧。
新建一个Trigger的时候,简单的定时任务如下:

 Trigger trigger =  TriggerBuilder.newTrigger()  
                .withIdentity("trigger5_1", "tGroup5")
                .startAt(DateBuilder.futureDate(10, IntervalUnit.SECOND))
                .forJob(jobDetail)
                .build();  

如果没有调用 .withSchedule()方法的话,会在创建的时候报如下错误:

java.lang.RuntimeException: org.quartz.SchedulerException: Repeat Interval cannot be zero.
	at org.nutz.lang.Lang.wrapThrow(Lang.java:184)
	at org.nutz.integration.quartz.QuartzManagerImpl.add(QuartzManagerImpl.java:142)
	at com.xiaomo.main.module.QuartzModule.add(QuartzModule.java:60)

然后一步步调试进去,发现是这样的,在org.nutz.integration.quartz.Quartzs中方法makeSimpleTrigger(String jobName, String jobGroup, int fixedRate, int count, long initialDelay)中

 public static SimpleTrigger makeSimpleTrigger(String jobName, String jobGroup, int fixedRate, int count, long initialDelay) {
        SimpleScheduleBuilder schedule = SimpleScheduleBuilder.simpleSchedule();
        if (fixedRate > 0)
            schedule.withIntervalInSeconds(fixedRate);
        if (count > 0) {
            schedule.withRepeatCount(count);
        } else {
            schedule.repeatForever();
        }
        TriggerBuilder<SimpleTrigger> trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(schedule);
        if (initialDelay > 0) 
            trigger.startAt(new Date(System.currentTimeMillis() + initialDelay*1000));
        return trigger.build();
    }

如果 count > 0 ,才注入repeatCount,否则就设置为 -1(SimpleTrigger.REPEAT_INDEFINITELY) ,由于默认值就是 0 ,所以就会导致把repeatCount设置为 -1,而此时repeatInterval 取了默认值 0 ,所以此时

repeatCount = -1
repeatInterval = 0

之后,在org.quartz.core.QuartzScheduler的方法public void scheduleJobs(Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace) throws SchedulerException中,会调用 opt.validate(),来核验 repeat值的合法性,方法是org.quartz.impl.triggers.SimpleTriggerImpl中的validate()

    @Override
    public void validate() throws SchedulerException {
        super.validate();

        if (repeatCount != 0 && repeatInterval < 1) {
            throw new SchedulerException("Repeat Interval cannot be zero.");
        }
    }

此时就会抛出上述异常。其实 这个 (repeatCount != 0 && repeatInterval < 1) 的意思就是,这个任务会在未来隔repeatInterval时间来执行repeatCount次,(注,第一次不算在repeatCount中的),所以就相当于未来执行无限次但是间隔时间为0,任务就无法执行,就抛出异常了。

解决方法:
在创建Trigger的时候,增加一个.withSchedule()方法,如下:

       Trigger trigger =  TriggerBuilder.newTrigger()  
                .withIdentity("trigger5_1", "tGroup5")               .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                		.withIntervalInSeconds(1)
                		.withRepeatCount(0)
                		)
                .startAt(DateBuilder.futureDate(10, IntervalUnit.SECOND))
                .forJob(jobDetail)
                .build();  

或者把nutz-integration-quartz的源码中org.nutz.integration.quartz.Quartzs中方法makeSimpleTrigger改一下,把count > 0 改成 count >= 0 就可以了。

我这边使用的nutz-integration-quartz是1.r.65的,quartz版本是2.2.3的。
找了这个问题一个下午,总算解决了,分享出来,大家不会再踩同样的坑了。

添加回复
请先登陆
回到顶部