View Javadoc

1   package com.atlassian.scheduler.quartz2;
2   
3   import org.quartz.JobDetail;
4   import org.quartz.JobPersistenceException;
5   import org.quartz.impl.jdbcjobstore.JobStoreTX;
6   import org.quartz.spi.OperableTrigger;
7   import org.slf4j.Logger;
8   import org.slf4j.LoggerFactory;
9   
10  import javax.annotation.Nullable;
11  import java.sql.Connection;
12  import java.util.concurrent.locks.ReentrantLock;
13  
14  import static com.atlassian.scheduler.core.util.LogWarn.logWarn;
15  
16  /**
17   * Quartz breaks if a bad job class is seen during scheduler recovery (at startup),
18   * leading to the scheduler failing to start.  This patches the normal {@code JobStoreTX}
19   * to avoid the problem by logging a warning instead of failing to start the scheduler.
20   */
21  public class Quartz2HardenedJobStore extends JobStoreTX {
22      private static final Logger LOG = LoggerFactory.getLogger(Quartz2HardenedJobStore.class);
23  
24      private final ReentrantLock recoverJobsLock = new ReentrantLock();
25  
26      @Override
27      protected void recoverJobs() throws JobPersistenceException {
28          recoverJobsLock.lock();
29          try {
30              super.recoverJobs();
31          } finally {
32              recoverJobsLock.unlock();
33          }
34      }
35  
36      @Override
37      protected void storeTrigger(Connection conn, OperableTrigger newTrigger, @Nullable JobDetail job,
38                                  boolean replaceExisting, String state, boolean forceState, boolean recovering)
39              throws JobPersistenceException {
40          try {
41              super.storeTrigger(conn, newTrigger, job, replaceExisting, state, forceState, recovering);
42          } catch (JobPersistenceException jpe) {
43              // We don't actually expect this lock to ever be contended.  We just need to know if this thread
44              // has traversed "recoverJobs" on the way here, and lock ownership is a convenient way to find out.
45              if (!recoverJobsLock.isHeldByCurrentThread()) {
46                  throw jpe;
47              }
48              logWarn(LOG, "Caught an exception storing trigger during scheduler recovery", jpe);
49          }
50      }
51  }