Using the Quartz scheduler with WebSphere Application Server and the Spring Framework

By Stefan Gybas | 09 March 2014

Quartz is a popular Java open source job scheduler that supports clustering, that means is can make sure that a job is run on exactly one node in a cluster. Many people run Quartz on WebSphere Application Server but face problems when their Quartz jobs try to access JNDI resources or try to participate in a JTA transaction.

You get an exception with the following text:

javax.naming.ConfigurationException: A JNDI operation on a “java:” name cannot be completed because the server runtime is not able to associate the operation’s thread with any J2EE application component. This condition can occur when the JNDI client using the “java:” name is not executed on the thread of a server application request. Make sure that a J2EE application does not execute JNDI operations on “java:” names within static code blocks or in threads created by that J2EE application. Such code does not necessarily run on the thread of a server application request and therefore is not supported by JNDI operations on “java:” names. [Root exception is javax.naming.NameNotFoundException: Name comp/env/[…] not found in context “java:”.]

IBM’s famous document Using Spring and Hibernate with WebSphere Application Server says about scheduling:

Other packages, such as quartz and the JDK Timer, start unmanaged threads and should be avoided.

The Spring Framework chapter in the WAS 8.0 documentation states the reasons for avoiding unmanaged threads. One point is

Unmanaged threads do not have access to Java EE contextual information.

To make Quartz fully supported on WebSphere you need to make sure that no unmanaged threads are started. Your jobs then have access to JNDI resources and can participate in JTA transactions (which require a JNDI lookup to java:comp/UserTransaction).

It has long been possible to specify a custom thread pool that delegates to a CommonJ work manager to create managed threads. However, Quartz starts some internal threads from which the actual jobs are started. If the Quartz-internal threads are unmanaged the JEE context is lost and can’t be propagated to the job threads, even if they are managed.

The two issues QTZ-113 and QTZ-194 were fixed in Quartz 2.1 by introducing a new SPI: org.quartz.spi.ThreadExecutor. To get the Quartz-internal threads managed, you need to set two properties in your Quartz configuration:

org.quartz.threadExecutor.class=org.quartz.commonj.WorkManagerThreadExecutor
org.quartz.threadExecutor.workManagerName=wm/default

Important: Don’t use the java:comp/env prefix for the JNDI work manager name. As of Quartz 2.2.1, you’ll get a warning in WebSphere’s SystemOut.log log file after a couple of minutes:

ThreadMonitor W   WSVR0605W: Thread "WorkManager.DefaultWorkManager : 1"
  (000001eb) has been active for 736400 milliseconds and may be hung.
  There is/are 1 thread(s) in total in the server that may be hung.
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:196)
        at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:410)
        at org.quartz.commonj.DelegatingWork.run(WorkManagerThreadExecutor.java:97)
        at com.ibm.ws.asynchbeans.J2EEContext$RunProxy.run(J2EEContext.java:265)
        at java.security.AccessController.doPrivileged(AccessController.java:229)
        at com.ibm.ws.asynchbeans.J2EEContext.run(J2EEContext.java:1165)
        at com.ibm.ws.asynchbeans.WorkWithExecutionContextImpl.go(WorkWithExecutionContextImpl.java:199)
        at com.ibm.ws.asynchbeans.CJWorkItemImpl.run(CJWorkItemImpl.java:236)
        at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1691)

I have created a bug report with a fix for this in Terracotta’s JIRA: QTZ-433. You should use your own ThreadExecutor implementation until this bug gets fixed in a future Quartz version.

Integration with the Spring Framework

The Spring Framework offers support for Quartz using SchedulerFactoryBean:

<bean id="quartzScheduler"
    class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  <property name="taskExecutor" ref="taskExecutor" />
  <property name="quartzProperties">
    <props>
      <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop>
      <prop key="org.quartz.threadExecutor.class">org.quartz.commonj.WorkManagerThreadExecutor</prop>
      <prop key="org.quartz.threadExecutor.workManagerName">wm/default</prop>
    </props>
  </property>
</bean>

You can set the task executor to a CommonJ work manager so the threads that will be created for your Quartz jobs are managed by the application server:

<bean id="taskExecutor"
    class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
  <property name="resourceRef" value="true" />
  <property name="workManagerName" value="wm/default" />
</bean>

A sample project is available from my GitHub repository.

Category: Java | Tags: WAS, Spring, Threads