无法检索作业,因为没有找到所需的类,即使先前的触发器已成功触发



我有一个用Quartz定义的CRON触发器,它成功地触发了几次,并在一些周期后以错误状态结束,并带有以下消息(类名和包名已被编辑):

org.quartz.JobPersistenceException: Couldn't retrieve job because a required class was not found: xxx.xxx.xxx.MyQuartzJob
at org.quartz.impl.jdbcjobstore.JobStoreSupport.retrieveJob(JobStoreSupport.java:1393) [quartz-2.3.2.jar!/:na]
at org.quartz.impl.jdbcjobstore.JobStoreSupport.acquireNextTrigger(JobStoreSupport.java:2864) [quartz-2.3.2.jar!/:na]
at org.quartz.impl.jdbcjobstore.JobStoreSupport$41.execute(JobStoreSupport.java:2805) [quartz-2.3.2.jar!/:na]
at org.quartz.impl.jdbcjobstore.JobStoreSupport$41.execute(JobStoreSupport.java:2803) [quartz-2.3.2.jar!/:na]
at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3864) [quartz-2.3.2.jar!/:na]
at org.quartz.impl.jdbcjobstore.JobStoreSupport.acquireNextTriggers(JobStoreSupport.java:2802) [quartz-2.3.2.jar!/:na]
at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:287) [quartz-2.3.2.jar!/:na]
Caused by: java.lang.ClassNotFoundException: xxx.xxx.xxx.MyQuartzJob
at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[na:1.8.0_302]
at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[na:1.8.0_302]
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151) ~[app.jar:2.4.0-SNAPSHOT]
at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_302]
at java.lang.Class.forName0(Native Method) ~[na:1.8.0_302]
at java.lang.Class.forName(Class.java:348) ~[na:1.8.0_302]
at org.springframework.util.ClassUtils.forName(ClassUtils.java:284) ~[spring-core-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at org.springframework.scheduling.quartz.ResourceLoaderClassLoadHelper.loadClass(ResourceLoaderClassLoadHelper.java:81) ~[spring-context-support-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at org.springframework.scheduling.quartz.ResourceLoaderClassLoadHelper.loadClass(ResourceLoaderClassLoadHelper.java:87) ~[spring-context-support-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.selectJobDetail(StdJDBCDelegate.java:852) ~[quartz-2.3.2.jar!/:na]
at org.quartz.impl.jdbcjobstore.JobStoreSupport.retrieveJob(JobStoreSupport.java:1390) [quartz-2.3.2.jar!/:na]

一旦发生此错误,触发器将自己更新为ERROR状态并且不再触发。这里的奇怪之处在于,触发器已经成功触发了几次(有时多达4次),但在下一次迭代时,却突然无法加载类。如果我手动将其状态更新为WAITING,它在更新后立即触发一次,并恢复其调度:它工作了几个周期,并且在某些时候由于我上面复制的错误而无法再次启动,并将自己更新为ERROR状态。

我不知道为什么,或者如何解决这个问题。在Quartz数据库上没有并发访问,因为我们运行的是单个服务器实例,所以我不明白为什么在部署的服务器的同一版本上,类会被成功找到并加载几次,然后又没有。

数据库中的完全限定类名是正确的(包名+类名)。

如有任何建议,我将不胜感激。如有需要,请随时询问更多细节。

这是Spring Boot应用程序中遇到的一个非常常见的问题,其中Spring Quartz调度器工厂创建了一个默认使用org.springframework.scheduling.quartz.ResourceLoaderClassLoadHelper作为类加载助手的Quartz调度器实例。可以在堆栈跟踪中看到这个类加载帮助器。Quartz使用类加载助手来加载作业实现类。

要解决这个问题,请在您的quartz.properties中添加以下属性:

org.quartz.scheduler.classLoadHelper.class =org.quartz.simpl.CascadingClassLoadHelper

我试图理解为什么我仍然看到提到旧ClassLoadHelper类在配置中更改后的错误,事实证明我们有第二个"隐藏";在我们的云提供商上运行我们的应用程序的实例,使用几个月前的旧版本代码。

它反复尝试并失败触发触发器,因为此时Quartz Job类不存在,因此在实际最新实例使用的同一数据库中将触发器设置为错误状态。要解决这个问题,我们只需要去掉无关的实例。

对于误导的信息,我很抱歉,当发布这个问题时,我不知道这个其他实例。

可能您的qrtz_job_details表中存在一些不正确的数据。例如,重复的工作名称。请查看qrtz_job_details, qrtz_triggers表数据

最新更新