title: Avoiding misfires with Quartz
body: <p>I'm facing a painful problem with Quartz and misfires.</p>
  
  <p>My App creates allows user to create CronTrigger and SimpleTrigger Jobs.</p>
  
  <p>Each Job can be paused/resumed (using Scheduler.pauseJob and Scheduler.resumeJob)</p>
  
  <p>The scheduler itself can be set to standby.</p>
  
  <p>We'd like to discard any misfires :</p>
  
  <ul>
  <li>When scheduler is in standby</li>
  <li>When job is paused</li>
  <li>When the application is stopped</li>
  </ul>
  
  <p>As explained in this blog post <a href="http://www.nurkiewicz.com/2012/04/quartz-scheduler-misfire-instructions.html" rel="noreferrer">http://www.nurkiewicz.com/2012/04/quartz-scheduler-misfire-instructions.html</a>, I've tried </p>
  
  <ul>
  <li>withMisfireHandlingInstructionDoNothing policy for CronTrigger </li>
  <li>withMisfireHandlingInstructionNextWithRemainingCount for SimpleTrigger</li>
  </ul>
  
  <p>but none could discard misfires.</p>
  
  <p>I'm currently using an ugly workaround in job execute method:</p>
  
  <pre><code>public void execute(JobExecutionContext context) throws JobExecutionException {
      Date dateNow = new Date();
      long diff = dateNow.getTime() - context.getScheduledFireTime().getTime();
      if (diff &gt; 500)
      {
           //its a misfire
           return;
      }
  
      /* rest of job execution code */
  </code></pre>
  
  <p>When scheduledFireTime is more than 500ms older than now, discard it.</p>
  
  <p>But it seems that sometimes, in production, this allows some jobs to be executed (it has been reported that occurs when app is restarted)</p>
  
  <p>Could that be possible ?
  Is there any pretty way to avoid misfires ?</p>
  
  <p>Quartz version : 2.1.7 (In a Spring 3.2.5 app)</p>
  
  <p>quartz.properties</p>
  
  <pre><code>org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
  org.quartz.jobStore.dataSource=psqldatasource
  org.quartz.dataSource.psqldatasource.driver=${db.driver}
  org.quartz.dataSource.psqldatasource.URL=${db.url}
  org.quartz.dataSource.psqldatasource.user=${db.usr}
  org.quartz.dataSource.psqldatasource.password=${db.pwd}
  org.quartz.threadPool.threadCount = 3
  
  org.quartz.jobStore.useProperties = false
  org.quartz.jobStore.driverDelegateClass =  org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
  </code></pre>
  
  <p>for Cron :</p>
  
  <pre><code> JobDetail job = JobBuilder.newJob(JobLauncher.class)
   .withIdentity(jobIdentifierBean.getNameJob(), jobIdentifierBean.getNameGroup())
   .usingJobData(...) //defining some jobData key/values
   .build();
  
   Trigger trigger = TriggerBuilder.newTrigger()
   .withIdentity(name, group)
   .startNow()
   .withSchedule(CronScheduleBuilder.cronSchedule(strCronExpression).withMisfireHandlingInstructionDoNothing())
   .build();
  
   try {
      scheduler.scheduleJob(job, trigger);
  } catch (SchedulerException e) {
      throw e;
  }
  </code></pre>
  
  <p>for SimpleTrigger (job is defined as in cron case)</p>
  
  <pre><code>    //avoid first fire
      GregorianCalendar g = new GregorianCalendar();
      switch (enumDelayUnits) {
          case Days:
              g.add(GregorianCalendar.HOUR, delay * 24);
              break;
          case Hours:
              g.add(GregorianCalendar.HOUR, delay);
              break;
          case Minutes:
              g.add(GregorianCalendar.MINUTE, delay);
              break;
          case Seconds:
              g.add(GregorianCalendar.SECOND, delay);
              break;
          default:
              throw new ServiceException("Unknow delay type");
      }
  
      Trigger trigger = TriggerBuilder.newTrigger()
              .withIdentity(jobIdentifierBean.getNameTrigger(), jobIdentifierBean.getNameGroup())
              .startAt(g.getTime())
              .withSchedule(getSimpleScheduleBuilder(delay, enumDelayUnits, repeatForever))
              .build();
      try {
          scheduler.scheduleJob(job, trigger);
      } catch (SchedulerException e) {
          throw e;
      }
  
  private SimpleScheduleBuilder getSimpleScheduleBuilder(int delay, EnumDelayUnits enumDelayType, boolean repeatForever) throws ServiceException, Exception
  {
      SimpleScheduleBuilder simpleScheduleBuilder;
  
      simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
      switch (enumDelayType) {
      case Days:
          simpleScheduleBuilder.withIntervalInHours(24 * delay);
          break;
      case Hours:
          simpleScheduleBuilder.withIntervalInHours(delay);
          break;
      case Minutes:
          simpleScheduleBuilder.withIntervalInMinutes(delay);
          break;
      case Seconds:
          simpleScheduleBuilder.withIntervalInSeconds(delay);
          break;
      default:
          serviceError("Unknown delay " + enumDelayType);
      }
      if(repeatForever)
      {
          simpleScheduleBuilder.repeatForever();
      }
  
      simpleScheduleBuilder = simpleScheduleBuilder.withMisfireHandlingInstructionNextWithRemainingCount();
  
      return simpleScheduleBuilder;
  }
  </code></pre>