使用Quartz的调度程序不会立即调用

时间:2014-05-22 20:56:45

标签: quartz-scheduler

我使用quartz-2.2.1.jar配置了一个调度程序,每10分钟重复一次。它工作正常并且每10分钟触发一次,但第一次触发不会立即发生。第一次触发仅在10分钟后发生。

有人可以帮我解决这个问题吗?

代码段:

JobDetail jobDetail = JobBuilder.newJob()
.withIdentity("key_expiration_email_notifier")
.ofType(KeyExpirationEmailNotifier.class).build();

Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("key_expiration_email_notifier")
.forJob(jobDetail).usingJobData(jobDataMap)
.withSchedule(SimpleScheduleBuilder.repeatMinutelyForever(10))
.startAt(new Date()).build();

Scheduler scheduler = SpringContext.getBean("schedulerFactoryBean");
scheduler.scheduleJob(jobDetail, trigger);

2 个答案:

答案 0 :(得分:0)

目前尚不清楚是否在执行上述代码之前启动Quartz调度程序 ?如果没有,那么它将解释为什么你的触发器没有立即执行,即使你有startAt = new Date()。

我还建议确保创建的触发器的失火指令设置为FIRE_NOW,因为这会使调度程序在发生失火时执行触发器(例如因为错过了初始的'新Date()'时间)。如果这没有帮助,你可能想使用startAt =(new Date()+几秒)来稍微执行第一次执行。

答案 1 :(得分:0)

我也遇到过这个问题,并为此找到了一个小的解决方法。这是一个冷启动问题。 实现这一目标的方法是首先获得预定的开火时间:

Date scheduledCurrentJobTime = jobExecutionContext.getScheduledFireTime();  

然后,当我们计划了开火时间时,我们可以为未实现的方法制定一个简单的解决方法来获取之前的开火时间:

public class CustomCronExpression extends CronExpression {  
    private static final String DELIMITER = " ";  
 /** 
  * Constructs a new <CODE>CronExpression</CODE> based on the specified 
  * parameter. 
  * 
  * @param cronExpression String representation of the cron expression the 
  *       new object should represent 
  * @throws java.text.ParseException if the string expression cannot be parsed into a valid 
  *         <CODE>CronExpression</CODE> 
  */  

  public CustomCronExpression(String cronExpression) throws ParseException {  
   super(cronExpression);  
  }  

  // here we can override this method and call it in future for the first-time   
  // launch to get previous time  
    @Override  
    public Date getTimeBefore(Date targetDate) {  
        Date nextFireTime = getTimeAfter(targetDate);  

    Calendar calendar = Calendar.getInstance(getTimeZone());  
    calendar.setTime(nextFireTime);  
    calendar.add(Calendar.SECOND, -1);  

    int dateUnit = getDateUnitCronExpression();  

  switch (dateUnit) {  
      case -1:  
          break;  
      case MINUTE:  
          calendar.add(Calendar.MINUTE, -1);  
          break;  
      case HOUR:  
       calendar.add(Calendar.HOUR_OF_DAY, -1);  
       break;  
      case DAY_OF_MONTH:  
      case DAY_OF_WEEK:  
       calendar.add(Calendar.DAY_OF_YEAR, -1);  
       break;  
      case MONTH:  
       calendar.add(Calendar.MONTH, -1);  
       break;  
      default:  
       calendar.add(Calendar.YEAR, -1);  
       break;  
    }  

    Date previousDate = getTimeAfter(calendar.getTime());  
    Date afterPreviousDate = getTimeAfter(previousDate);  

    return findPreviousJobFireDate(afterPreviousDate, targetDate);  
  }  

  private int getDateUnitCronExpression() {  
    String cronExpression = getCronExpression();  
    if (StringUtils.isEmpty(cronExpression)) {  
      return -1;  
    }  

    String[] expression = cronExpression.split(DELIMITER);

    return findDateUnitToWorkWith(expression);  
  }  

  private Date findPreviousJobFireDate(Date afterFuturePreviousDate, Date targetDate) {  
    Date futureDate = afterFuturePreviousDate;  
    Date resultDate = targetDate;  

    while (true) {  
      if (futureDate.equals(targetDate)) {  
       return resultDate;  
      } else {  
       resultDate = futureDate;  
       futureDate = getTimeAfter(resultDate);

       // prevent NPE and return current job time  
       if(futureDate == null) {  
         return resultDate;  
       }  
      }  
    }  
  }  

  private int findDateUnitToWorkWith(String[] expression) {  
   // * - represents the unit of date in the cron expression  
    // [0]Sec [1]Min [2]Hour [3]DayOfMonth [4]Month [5]DayOfWeek [6]Year  
    for (int i = 0, n = expression.length; i < n; i++) {  
      if (expression[i].equals("*")) {  
       return i;  
      }  
    }  
    return YEAR;  
  }   
}

findDateUnitToWorkWith(String[] expression) - 此方法将在cron表达式中第一次找到*。当我们找到它时 - 首先我们应该获得下一个开火时间,然后从下一个开火时间中减去一个日期单位。

我在博客上详细介绍了这一点:Quartz-scheduler cold-start problem