Skip to content
Advertisement

Couldn’t retrieve job because a required class was not found, even though previous triggers fired successfully

I have a CRON trigger defined with Quartz, which successfully fires several times and ends up in error state after some cycles, with the following message (class names and package names have been redacted):

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]

Once this error happens, the trigger updates itself to ERROR state and won’t fire anymore. The strange thing here is that the trigger already fired successfully a few times (sometimes up to 4 times) and suddenly, at its next iteration, fails to load the class. If I manually update its state to WAITING again it triggers once right after the update, and resumes its schedule: it works for a few cycles, and at some point fails to launch again with the error I copied above, and updates itself to ERROR state.

I have no clue as to why, or how to fix this. There is no concurrency of access on the Quartz database as we are running a single server instance, so I don’t understand why the class would be successfully found and loaded several times and then not, on the same version of the deployed server.

Fully qualified classname in the database is correct (package name + class name).

Any advice on this would be greatly appreciated. Feel free to ask more details if needed.

Advertisement

Answer

This is a very common problem encountered in Spring Boot applications where the Spring Quartz scheduler factory creates a Quartz scheduler instance that by default uses org.springframework.scheduling.quartz.ResourceLoaderClassLoadHelper as the class load helper. This class load helper can be seen in your stack trace. Quartz uses the class load helper to load job implementation classes.

To fix the issue, please add the following property to your quartz.properties:

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

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement