石英触发器未触发

huangapple go评论149阅读模式
英文:

Quartz Trigger Not Firing

问题

我有一个运行在Tomcat上的Java Web应用程序
我正在使用`Quartz 2.3.0`(已更新为`2.3.2`,仍然不起作用)。
我使用以下代码初始化Quartz使用了`Properties`:

Properties properties = new Properties();
properties.put("org.quartz.scheduler.instanceName", hostname);
properties.put("org.quartz.scheduler.instanceId", hostname);
properties.put("org.quartz.threadPool.threadCount", "5");
properties.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
properties.put("org.quartz.jobStore.isClustered", "true");
properties.put("org.quartz.jobStore.misfireThreshold", "600000");
properties.put("org.quartz.jobStore.clusterCheckinInterval", "100000");
properties.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
properties.put("org.quartz.jobStore.dataSource", "QCP");
properties.put("org.quartz.dataSource.QCP.connectionProvider.class", "mypackage.quartz.QuartzConnectionProvider");
properties.put("org.quartz.plugin.shutdownhook.class", "org.quartz.plugins.management.ShutdownHookPlugin");
properties.put("org.quartz.plugin.shutdownhook.cleanShutdown", "false");
properties.put("org.quartz.scheduler.skipUpdateCheck", "true");

Scheduler quartzScheduler = new StdSchedulerFactory(properties).getScheduler();

quartzScheduler.start();

然后我添加了一个任务:

JobDetail runnableDetail = JobBuilder.newJob(RunnableJob.class)
            .withIdentity("runnable_JOB", "runnable")
            .storeDurably(true)
            .requestRecovery(false)
            .build();
quartzScheduler.addJob(runnableDetail, true);

接着,为它创建了一个触发器:

String uuid = UUID.randomUUID().toString();
Trigger trigg = TriggerBuilder.newTrigger()
            .withIdentity("runnable_TRIGGER_" + uuid, "runnable")
            .forJob("runnable_JOB", "runnable")
            .withSchedule(SimpleScheduleBuilder.simpleSchedule().withMisfireHandlingInstructionFireNow().withRepeatCount(0))
            .startAt(DateBuilder.futureDate(startDelaySeconds, IntervalUnit.SECOND))
            .build();
quartzScheduler.scheduleJob(trigg);

这是我的RunnableJob类:

public class RunnableJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        try {
            //一些代码
        } catch (Exception e) {
            //记录异常
        };
    }
}

但触发器从不触发,当我查看MySQL数据库中的QRTZ_TRIGGERS表时,可以看到触发器和任务已经成功添加,但在触发触发器的正确时间到来时,我看到NEXT_FIRE_TIME列会改变。

我已经阅读过这里并检查了以下值:

quartzScheduler.isStarted();
quartzScheduler.isInStandbyMode();

它们的值分别为truefalse,这意味着调度器处于正确的状态,而且我的Trigger状态为WAITING

更奇怪的是,它在我的系统上运行良好,但在部署到生产系统时却失败了。

我在我的系统上使用的是Windows 10,而服务器上使用的是CentosTomcat 9,并且我正在使用Java 14

更新:
经过一些更改(并非有关触发器和任务创建的方式),现在NEXT_FIRE_TIME不会更新,我检查了catalina.out,里面充满了这个异常:

31-Aug-2020 11:04:56.986 INFO [QuartzScheduler_demo123.domain.co-demo123.domain.co_ClusterManager] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading 非法访问此Web应用程序实例已经停止无法加载[META-INF/services/javax.naming.spi.InitialContextFactory]以下堆栈跟踪被抛出用于调试以及尝试终止引发非法访问的线程
    java.lang.IllegalStateException: 非法访问此Web应用程序实例已经停止无法加载[META-INF/services/javax.naming.spi.InitialContextFactory]
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1385)
    ...
Caused by: java.lang.NoClassDefFoundError: java/lang/Thread
    at mypackage.quartz.QuartzConnectionProvider.getConnection(QuartzConnectionProvider.java:25)
    ...

问题在重新启动Tomcat服务器后仍未解决。

更新2:
问题似乎来自我正在尝试从中获取连接的数据源。我的Tomcat实例在server.xml文件中使用不同的<Host>标签进行了定义,它们的资源在每个应用程序实例的<Context>标签中进行了定义:

<Resource name="jdbc/mysql/hamkelasi" auth="Container" type="javax.sql.DataSource"
    
    initialSize="1" maxTotal="50" maxIdle="1" 
    maxWaitMillis="20000" removeAbandonedOnBorrow="true" removeAbandonedTimeout="600"
    validationQuery="select now();" timeBetweenEvictionRunsMillis="1800000"

    username="user" password="pass" driverClassName="com.mysql.jdbc.Driver"
    url="..."
    />

在我的ContextListener中,我实例化了一个javax.naming.InitialContext,然后使用.lookup(poolLookupString)。我尝试过不同的方法,如缓存InitialContext或缓存数据源,但没有成功。

问题仅出现在生产服务器上,配置和库都相同。错误发生在启动QuartzScheduler时,当它尝试从数据库获取连接时。

错误信息中出现了一个非常奇怪的错误:

java.lang.NoClassDefFoundError: java/lang/Thread

并且我只在一个应用程序上使用QuartzScheduler(仅用于测试目的)。


<details>
<summary>英文:</summary>
I have a java web application which runs on tomcat.
I am using `Quartz 2.3.0` 
(Updated to `2.3.2`, still not working)
I am initializing quartz with `Properties` as follows:
Properties properties = new Properties();
properties.put(&quot;org.quartz.scheduler.instanceName&quot;, hostname);
properties.put(&quot;org.quartz.scheduler.instanceId&quot;, hostname);
properties.put(&quot;org.quartz.threadPool.threadCount&quot;, &quot;5&quot;);
properties.put(&quot;org.quartz.jobStore.class&quot;, &quot;org.quartz.impl.jdbcjobstore.JobStoreTX&quot;);
properties.put(&quot;org.quartz.jobStore.isClustered&quot;, &quot;true&quot;);
properties.put(&quot;org.quartz.jobStore.misfireThreshold&quot;, &quot;600000&quot;);//until 10 minutes, dont count as a misfire
properties.put(&quot;org.quartz.jobStore.clusterCheckinInterval&quot;, &quot;100000&quot;);
properties.put(&quot;org.quartz.jobStore.driverDelegateClass&quot;, &quot;org.quartz.impl.jdbcjobstore.StdJDBCDelegate&quot;);
properties.put(&quot;org.quartz.jobStore.dataSource&quot;, &quot;QCP&quot;);
properties.put(&quot;org.quartz.dataSource.QCP.connectionProvider.class&quot;, &quot;mypackage.quartz.QuartzConnectionProvider&quot;);
properties.put(&quot;org.quartz.plugin.shutdownhook.class&quot;, &quot;org.quartz.plugins.management.ShutdownHookPlugin&quot;);//This plugin catches the event of the JVM terminating (such as upon a CRTL-C) and tells the scheuler to shutdown.
properties.put(&quot;org.quartz.plugin.shutdownhook.cleanShutdown&quot;, &quot;false&quot;);
properties.put(&quot;org.quartz.scheduler.skipUpdateCheck&quot;, &quot;true&quot;);
Scheduler quartzScheduler quartzScheduler = new StdSchedulerFactory(properties).getScheduler(); 	
quartzScheduler.start();
then I add a job:
JobDetail runnableDetail = JobBuilder.newJob(RunnableJob.class)
.withIdentity(&quot;runnable_JOB&quot;, &quot;runnable&quot;)
.storeDurably(true)
.requestRecovery(false)
.build();
quartzScheduler.addJob(runnableDetail , true);
and then create a trigger for it like this:
String uuid = UUID.randomUUID().toString();
Trigger trigg = TriggerBuilder.newTrigger()
.withIdentity(&quot;runnable_TRIGGER_&quot;+uuid, &quot;runnable&quot;)
.forJob(&quot;runnable_JOB&quot;, &quot;runnable&quot;)
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withMisfireHandlingInstructionFireNow().withRepeatCount(0))
.startAt(DateBuilder.futureDate(startDelaySeconds , IntervalUnit.SECOND)) //startDelaySeconds is between 1-300
.build();
quartzScheduler.scheduleJob(trigg);
This is my `RunnableJob` class:
public class RunnableJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
try {
//some code
} catch (Exception e) {
//log the exception
};
}
}
But the trigger never fires and when I see the `QRTZ_TRIGGERS` table my MySQL database, I can see that the trigger and the job has been added successfully, but when the right time comes to fire the trigger, I see that after some seconds the `NEXT_FIRE_TIME` column changes.
I have already read [this][1] and checked these values:
quartzScheduler.isStarted();
quartzScheduler.isInStandbyMode();
which was: `true` and `false` meaning that the scheduler is in the right state and also my `Trigger` state is `WAITING`.
The stranger thing is that it works fine on my system but it fails when I deploy it on the production system. 
I have `Windows 10` on my system and `Centos` and `Tomcat 9` on the server and I&#39;m using `Java 14`.
**UPDATE:**
After some changes(not to the way triggers and jobs are created), now the `NEXT_FIRE_TIME` doesn&#39;t update and I checked `catalina.out` and It&#39;s filled with this exception:
31-Aug-2020 11:04:56.986 INFO [QuartzScheduler_demo123.domain.co-demo123.domain.co_ClusterManager] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [META-INF/services/javax.naming.spi.InitialContextFactory]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [META-INF/services/javax.naming.spi.InitialContextFactory]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1385)
at org.apache.catalina.loader.WebappClassLoaderBase.findResources(WebappClassLoaderBase.java:985)
at org.apache.catalina.loader.WebappClassLoaderBase.getResources(WebappClassLoaderBase.java:1086)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.nextProviderClass(ServiceLoader.java:1197)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1222)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1266)
at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1301)
at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1386)
at java.naming/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:697)
at java.naming/javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
at java.naming/javax.naming.InitialContext.init(InitialContext.java:236)
at java.naming/javax.naming.InitialContext.&lt;init&gt;(InitialContext.java:184)
at mypackage.quartz.QuartzConnectionProvider.getConnection(QuartzConnectionProvider.java:25)
at org.quartz.utils.DBConnectionManager.getConnection(DBConnectionManager.java:108)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.getConnection(JobStoreSupport.java:780)
at org.quartz.impl.jdbcjobstore.JobStoreTX.getNonManagedTXConnection(JobStoreTX.java:71)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.doCheckin(JobStoreSupport.java:3307)
at org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager.manage(JobStoreSupport.java:3920)
at org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager.run(JobStoreSupport.java:3957)
- ClusterManager: Error managing cluster: Failed to obtain DB connection from data source &#39;QCP&#39;: java.lang.NoClassDefFoundError: java/lang/Thread
org.quartz.JobPersistenceException: Failed to obtain DB connection from data source &#39;QCP&#39;: java.lang.NoClassDefFoundError: java/lang/Thread [See nested exception: java.lang.NoClassDefFoundError: java/lang/Thread]
at org.quartz.impl.jdbcjobstore.JobStoreSupport.getConnection(JobStoreSupport.java:789)
at org.quartz.impl.jdbcjobstore.JobStoreTX.getNonManagedTXConnection(JobStoreTX.java:71)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.doCheckin(JobStoreSupport.java:3307)
at org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager.manage(JobStoreSupport.java:3920)
at org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager.run(JobStoreSupport.java:3957)
Caused by: java.lang.NoClassDefFoundError: java/lang/Thread
at mypackage.quartz.QuartzConnectionProvider.getConnection(QuartzConnectionProvider.java:25)
at org.quartz.utils.DBConnectionManager.getConnection(DBConnectionManager.java:108)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.getConnection(JobStoreSupport.java:780)
... 4 more
The problem did not solve with restarting the tomcat server.
**UPDATE 2:**
The problem seems to be from the data source which I&#39;m trying to get a connection from.
My tomcat instances are defined in `server.xml` file with different `&lt;Host&gt;` tags
and their resources are defined in the `&lt;Context&gt;` tag for each instance of my application:
&lt;Resource name=&quot;jdbc/mysql/hamkelasi&quot; auth=&quot;Container&quot; type=&quot;javax.sql.DataSource&quot;
initialSize=&quot;1&quot; maxTotal=&quot;50&quot; maxIdle=&quot;1&quot; 
maxWaitMillis=&quot;20000&quot; removeAbandonedOnBorrow=&quot;true&quot; removeAbandonedTimeout=&quot;600&quot;
validationQuery=&quot;select now();&quot; timeBetweenEvictionRunsMillis=&quot;1800000&quot;
username=&quot;user&quot; password=&quot;pass&quot; driverClassName=&quot;com.mysql.jdbc.Driver&quot;
url=&quot;...&quot;
/&gt;
And in my `ContextListener` I instantiate a `javax.naming.InitialContext` and then use `.lookup(poolLookupString)`. I tried different approaches here by caching the `InitialContext` or caching data sources but didn&#39;t succeed.
Still, the problem is only on the production server with the same configurations and the same libraries.
The error happens when I start the `QuartsScheduler` and when it tries to get a connection from the database. The server and the application are both working fine and only quartz fails with a really weird error saying:
java.lang.NoClassDefFoundError: java/lang/Thread
And also I&#39;m only using the `QuartzScheduler` on one of my applications (for test porpuses)
[1]: http://www.quartz-scheduler.org/documentation/2.3.1-SNAPSHOT/faq.html#questions-about-jobs
</details>
# 答案1
**得分**: 1
当石英作业线程接收到触发器时,它将锁定该行并更新其下一次触发时间,否则将进入错失触发状态。
如果您想深入挖掘代码并检查发生了什么
(链接:https://github.com/quartz-scheduler/quartz/blob/master/quartz-core/src/main/java/org/quartz/impl/jdbcjobstore/JobStoreSupport.java#L2831)
尝试为作业和触发器注册监听器,并检查是否已被捕获
链接:http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/tutorial-lesson-07.html
<details>
<summary>英文:</summary>
when the quartz job thread picks up the a trigger it will lock the row and updates its nextfire time, else it will go to missfire state.
If you want to dig down in to code and check whats happening 
(https://github.com/quartz-scheduler/quartz/blob/master/quartz-core/src/main/java/org/quartz/impl/jdbcjobstore/JobStoreSupport.java#L2831)
Try registering listeners for job and trigger and check if they are getting picked up
http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/tutorial-lesson-07.html
</details>
# 答案2
**得分**: 0
通过将我的MySQL连接器版本更新为8,并使用`com.mysql.cj.jdbc.Driver`,我的问题消失了,一切似乎都正常工作。
<details>
<summary>英文:</summary>
By updating my MySQL connector version to 8 and using `com.mysql.cj.jdbc.Driver` my problem vanished and everything seems to be working fine.
</details>

huangapple
  • 本文由 发表于 2020年8月26日 18:34:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/63595758.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定