Incorrect ContextClassLoader for CommonJ WorkManager worker threads when Quartz Scheduler is used [SPR-11125] #15751
When Quartz Scheduler is configured to utilize the CommonJ WorkManager, worker (WorkManager) threads have a different ContextClassLoader (CCL) than their caller.
The reason is that Spring creates the main Quartz thread during scheduler startup (startScheduler method in SchedulerFactoryBean) on its own and that means that this thread is unmanaged.
This means that while the unmanaged Quartz main thread will have correct CCL, managed WorkManager threads will not. They will get SystemClassLoader instead.
This should be corrected so that jobs can execute with correct CCL and thus especially (hardly modifiable) 3rd party code that may utilizes this class loader won't fail.
Most likely, the run method in the DelegatingWork class should be modified to explicitly propagate the CCL. Also a cleanup action that resets the CCL back at the end of the run would be essential.
Affects: 3.0.7, 3.2.5
2 votes, 4 watchers
The text was updated successfully, but these errors were encountered:
Juergen Hoeller commented
Revisiting this one, it's actually a good old Quartz problem since it's Quartz internally starting that scheduler thread, with Spring historically not being able to do much about it. Granted, we could explicitly pass the CCL to worker threads, but wouldn't it be preferable for the Quartz scheduler thread to be managed to begin with? I'll double-check Quartz 2.2 whether there's any way to override the scheduler thread now.
Note that these problems should not exist when using Spring's own scheduling support (
Peter H commented
This unmanaged threads problem causes also another issues (for example with JNDI lookups) so I took another look at it and there's actually a possibility to run all the Quartz controller threads as managed.
Give (to Quartz) the ThreadExecutor, in this case via Quartz properties org.quartz.threadExecutor.class=org.quartz.commonj.WorkManagerThreadExecutor and org.quartz.threadExecutor.workManagerName=
After this, it will run even its own controller threads on that work manager and things will be much better (CCL and Java EE context aren't lost) .
There are few culprits however
Note that I've found also this article http://gybas.com/2014/quartz-websphere-spring/ where the use of fully qualified JNDI name (indirect lookup) such as java:comp/env/wm/default is discouraged and the short one (direct lookup) like wm/default is recommended. Well, I did everything with the full name and didn't have any problem and don't see any good reason why there should be any (if you've got a resource reference for that work manager). You could probably make use of the resourceRef property (JndiLocatorSupport) here.
Note about the Quartz control threads (for those curious about how many of them may exist and how to determine the thread pool sizing):
So there could be 1-3 such threads depending on the scheduler configuration.
All the above is possible with Quartz 1.8.6 and 2.1.0 or later: https://jira.terracotta.org/jira/browse/QTZ-113 https://jira.terracotta.org/jira/browse/QTZ-194 https://jira.terracotta.org/jira/browse/QTZ-233