title: Recovering stuck quartz jobs
body: <p>I am facing some quartz jobs which get stuck, for example trying to connect forever. I am using a scheme where the idea is that I can detect these stuck jobs because their triggers have a nextFiretime far in the past. Then, i try to stop these threads by interrupting them. However, the interrupting doesn't seem to work, threads still run without that the nextFiretime gets updated.
  How do I interrupt them correctly?</p>
  
  <p>Job code:</p>
  
  <pre><code>protected AtomicReference&lt;Thread&gt; runningThread = null;
  
  /*
   * (non-Javadoc)
   * 
   * @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
   */
  @Override
  public void execute(JobExecutionContext context)
          throws JobExecutionException
  {
      runningThread = new AtomicReference&lt;Thread&gt;();
      try {
          this.runningThread.set(Thread.currentThread());
      } finally { 
          runningThread.set(null); 
      }
  }
  
  /*
   * (non-Javadoc)
   * 
   * @see org.quartz.InterruptableJob#interrupt()
   */
  @Override
  public void interrupt() throws UnableToInterruptJobException
  {
      Thread thread = runningThread.getAndSet(null);
      if (thread != null)
          thread.interrupt();
  }
  </code></pre>
  
  <p>The actual jobscheduler code for interrupting:</p>
  
  <pre><code>public int interruptLongRunningJobs(int ms) {
      int jobsInterrupted = 0;
      String jobsInterruptedList = "";
  
      Date limitInThePast = new Date(System.currentTimeMillis() - ms);
  
      Scheduler scheduler = this.getJobScheduler();
      // All scheduled jobs
      try {
          for (String groupName : scheduler.getJobGroupNames()) {
              for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
                  JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                  final List&lt;? extends Trigger&gt; triggers = scheduler.getTriggersOfJob(jobKey);
  
                  Date nextFireTime = null;
                  if (triggers.size() &gt; 0)
                  {
                      nextFireTime = triggers.get(0).getNextFireTime();
  
                      if(nextFireTime != null) {
                          if(nextFireTime.before(limitInThePast)) {
                              String jobString = jobDetail.getKey() + "@" + jobDetail.getJobClass().getSimpleName();
                              logger.debug("JobScheduler::interruptLongRunningJobs interrupting: " + jobString);
  
                              scheduler.interrupt(jobDetail.getKey());
  
                              if(!jobsInterruptedList.isEmpty()) {
                                  jobsInterruptedList += ", ";
                              }
                              jobsInterruptedList += jobString;
                              ++jobsInterrupted;
                          }
                      }
                  }
              }
          }
      } catch (SchedulerException e) {
          logger.debug("JobScheduler::interruptLongRunningJobs failed: " + e.getMessage());
      }
  
      if(jobsInterrupted&gt;0) {
          logger.debug("JobScheduler::interruptLongRunningJobs interrupted jobs#= " + jobsInterrupted);
  
          emailSomething("JobScheduler::interruptLongRunningJobs interrupted jobs#= " + jobsInterrupted, 
                  "These jobs have been interrupted and canceled because they exceeded the maximum running time as detected by triggers with nextFireTime in the past:\r\n" +  
                  jobsInterruptedList
          );
      }
      return jobsInterrupted;
  }
  </code></pre>