2

I am using Spring Batch with quartz. I have a bean destroy method which resets some flags in the database when the tomcat is shut down. Due to the following exception the destroy method is not called:

2013-06-18 18:11:16,505  INFO | schedulerFactoryBean_Worker-3 | org.quartz.core.JobRunShell  | Job DEFAULT.fundAdditionRequestJobDetail threw a JobExecutionException:  
org.quartz.JobExecutionException: Error while executing Spring Batch job 
at com.inmobi.sap.quartz.AbstractQuartzLauncher.executeInternal(AbstractQuartzLauncher.java:88) ~[AbstractQuartzLauncher.class:na]
    at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:113) ~[spring-context-support-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.quartz.core.JobRunShell.run(JobRunShell.java:213) ~[quartz-2.1.7.jar:na]
    at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:557) [quartz-2.1.7.jar:na]
Caused by: java.lang.NullPointerException: null
    at org.apache.commons.logging.impl.SLF4JLocationAwareLog.isTraceEnabled(SLF4JLocationAwareLog.java:60) ~[jcl-over-slf4j-1.6.1.jar:1.1.1]
    at org.springframework.transaction.support.TransactionSynchronizationManager.getResource(TransactionSynchronizationManager.java:139) ~[spring-tx-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.jdbc.datasource.DataSourceTransactionManager.doGetTransaction(DataSourceTransactionManager.java:180) ~[spring-jdbc-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:336) ~[spring-tx-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:417) ~[spring-tx-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:255) ~[spring-tx-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94) ~[spring-tx-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) ~[spring-aop-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at com.sun.proxy.$Proxy11.update(Unknown Source) ~[na:na]
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:340) ~[spring-batch-core-2.1.9.RELEASE.jar:na]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120) ~[spring-batch-core-2.1.9.RELEASE.jar:na]
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:49) ~[spring-core-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:114) ~[spring-batch-core-2.1.9.RELEASE.jar:na]
    at com.inmobi.sap.quartz.AbstractQuartzLauncher.executeInternal(AbstractQuartzLauncher.java:84) ~[AbstractQuartzLauncher.class:na]
    ... 3 common frames omitted 

2013-06-18 18:11:16,508 ERROR | schedulerFactoryBean_Worker-3 | org.quartz.core.ErrorLogger   | An error occured while marking executed job complete. job= 'DEFAULT.fundAdditionRequestJobDetail' 
org.quartz.JobPersistenceException: Failed to obtain DB connection from data source 'springNonTxDataSource.schedulerFactoryBean': java.lang.NullPointerException
    at org.quartz.impl.jdbcjobstore.JobStoreCMT.getNonManagedTXConnection(JobStoreCMT.java:173) ~[quartz-2.1.7.jar:na]
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3788) ~[quartz-2.1.7.jar:na]
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3760) ~[quartz-2.1.7.jar:na]
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.triggeredJobComplete(JobStoreSupport.java:3000) ~[quartz-2.1.7.jar:na]
    at org.quartz.core.QuartzScheduler.notifyJobStoreJobComplete(QuartzScheduler.java:1753) ~[quartz-2.1.7.jar:na]
    at org.quartz.core.JobRunShell.run(JobRunShell.java:281) ~[quartz-2.1.7.jar:na]
    at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:557) [quartz-2.1.7.jar:na]
Caused by: java.lang.NullPointerException: null
    at org.quartz.impl.jdbcjobstore.JobStoreCMT.getNonManagedTXConnection(JobStoreCMT.java:165) ~[quartz-2.1.7.jar:na]
    ... 6 common frames omitted

Config for dataSource:

<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource"
    destroy-method="close">
    <property name="driverClass" value="${batch.jdbc.driver}" />
    <property name="jdbcUrl" value="${batch.jdbc.url}" />
    <property name="username" value="${batch.jdbc.user}" />
    <property name="password" value="${batch.jdbc.password}" />
    <property name="idleConnectionTestPeriod" value="60" />
    <property name="idleMaxAge" value="240" />
    <property name="maxConnectionsPerPartition" value="${batch.jdbc.pool.size}" />
    <property name="minConnectionsPerPartition" value="4" />
    <property name="partitionCount" value="1" />
    <property name="acquireIncrement" value="3" />
    <property name="statementsCacheSize" value="0" />
    <property name="releaseHelperThreads" value="3" />
</bean>

Config for quartz:

<property name="quartzProperties">
            <props>
                    <prop key="org.quartz.scheduler.skipUpdateCheck">true</prop>
                    <!-- <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop> -->
                    <prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop>
                    <prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
                    </prop>
                    <prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop>
                    <prop key="org.quartz.jobStore.isClustered">true</prop>
                    <prop key="org.quartz.scheduler.instanceName">MyClusteredScheduler</prop>
                    <prop key="org.quartz.scheduler.instanceId">AUTO</prop>
            </props>
</property>

What I understand is while shutting down, dataSource is getting destroyed and logger is becoming null , resulting in NullPointerException. Not able to ascertain the reason for it, Please point me to right direction.

Prashant
  • 81
  • 7

1 Answers1

0

I have not tried with spring quartz. However, normally while using Quartz, we shutdown the quartz gracefully. By gracefully, I mean here that I will shutdown the scheduler only after executing all my pending jobs(jobs which are executed currently but have not yet marked their completion).

For graceful shutdowns, we pass attribute true while using method shutdown. Refer API here

I am eager to know how spring quartz implementation does this.

Shailesh Pratapwar
  • 4,054
  • 3
  • 35
  • 46
  • I have added this property for it to wait for jobs completion: 'code' true 'code' . And I am now not getting any exceptions , but still my bean destroy method is not getting called???? Also, I am getting _italic_ registered the JDBC driver [org.postgresql.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered. _italic_ . Note, I am using boncep and not dbcp for connection pooling and hopefully should not have got this error???? – Prashant Jun 19 '13 at 14:08
  • Also, I am using quartz 2.1.7 with spring 3.2.3 , where main thread joins on all other scheduler threads to complete. Still my bean destroy method is not getting called. – Prashant Jun 19 '13 at 14:17
  • I Guess Quartz latest version achieves connection pooling using c3p0 as compared to earlier used dbcp. So, I am a bit doubtful about boncep. Other option you can have is , to use your own connection pool provider. Quartz have facility of using [custom connection provider](http://quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigDataSources). With this, you can wrap the close method of boncep inside your custom beans destroy method. Hope you understood it. – Shailesh Pratapwar Jun 19 '13 at 17:47
  • I have switched to c3p0 but still I am seeing error in driver unable to register itself _italic_(registered the JDBC driver [org.postgresql.Driver] but failed to unregister it when the web application was stopped ). Also, with regards to spring , I see my bean being registered as singleton in logs , but while destroying the context , I don't see it betting destroyed , while I see all other beans destroyed. I am not sure why it is happening. :( – Prashant Jun 21 '13 at 06:32
  • I did found this link [link](http://quartz.10975.n7.nabble.com/Trigger-in-Limbo-td4648.html) to be useful in identifying the problem i.e. – Prashant Jun 24 '13 at 12:06
  • [link](http://quartz.10975.n7.nabble.com/Trigger-in-Limbo-td4648.html) to be useful in identifying the problem i.e. _italic_ jvm is shutting down, quartz is asked to shutdown gracefully but all its dependencies (datasource, transaction manager) that are shared with the rest of the application are being destroyed as it tries to let his last jobs complete... I tried out the options discussed in following [link]http://stackoverflow.com/questions/2730354/spring-scheduler-shutdown-error but still my bean destroy method is not getting called and exception mentioned in first post is coming. – Prashant Jun 24 '13 at 12:13