Announcement Announcement Module
Collapse
No announcement yet.
Quartz and JDBCJobStore Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Quartz and JDBCJobStore

    I'm trying to use Quartz with the JDBCJobStore but my triggers are not firing...

    This is my config:

    <bean name="updateDailyRatesJob"
    class="org.springframework.scheduling.quartz.JobDe tailBean">
    <property name="jobClass"
    value="com.class.DailyUpdateJob" />
    </bean>

    <bean name="scheduler"
    class="org.springframework.scheduling.quartz.Sched ulerFactoryBean">
    <property name="quartzProperties">
    <value>classpath:quartz.properties</value>
    </property>
    <property name="dataSource">
    <ref bean="dataSource" />
    </property>
    <property name="triggers">
    <list>
    <ref bean="simpleTrigger" />
    </list>
    </property>
    </bean>

    <bean id="simpleTrigger"
    class="org.springframework.scheduling.quartz.Simpl eTriggerBean">
    <!-- see the example of method invoking job above -->
    <property name="jobDetail" ref="updateDailyRatesJob" />
    <!-- 10 seconds -->
    <property name="startDelay" value="10000" />
    <!-- repeat every 50 seconds -->
    <property name="repeatInterval" value="50000" />
    </bean>

    The DailyUpdateJob is a StatefulJob that just prints to my log for the time being.

    This is my quartz.properties

    org.quartz.jobStore.class=org.quartz.impl.jdbcjobs tore.JobStoreCMT
    org.quartz.jobStore.driverDelegateClass=org.quartz .impl.jdbcjobstore.oracle.weblogic.WebLogicOracleD elegate
    org.quartz.jobStore.tablePrefix=QRTZ_
    org.quartz.jobStore.misfireThreshold=60000

    I'm using Weblogic 8.1 and Oracle 8.

    My log is full of this:

    2006-11-23 15:40:21,250 DEBUG org.springframework.jdbc.datasource.DataSourceUtil s - Returning JDBC Connection to DataSource
    2006-11-23 15:40:22,968 DEBUG org.springframework.scheduling.quartz.LocalDataSou rceJobStore - MisfireHandler: scanning for misfires...
    2006-11-23 15:40:23,078 DEBUG org.quartz.impl.jdbcjobstore.StdRowLockSemaphore - Lock 'TRIGGER_ACCESS' is desired by: QuartzScheduler_QuartzScheduler-NON_CLUSTERED_MisfireHandler
    2006-11-23 15:40:23,093 DEBUG org.quartz.impl.jdbcjobstore.StdRowLockSemaphore - Lock 'TRIGGER_ACCESS' is being obtained: QuartzScheduler_QuartzScheduler-NON_CLUSTERED_MisfireHandler
    2006-11-23 15:40:23,156 DEBUG org.quartz.impl.jdbcjobstore.StdRowLockSemaphore - Lock 'TRIGGER_ACCESS' given to: QuartzScheduler_QuartzScheduler-NON_CLUSTERED_MisfireHandler
    2006-11-23 15:40:23,265 INFO org.springframework.scheduling.quartz.LocalDataSou rceJobStore - Handling 1 trigger(s) that missed their scheduled fire-time.

    So, the scheduler is acquiring some sort of lock for fetching the job, and it is detecting the misfire, but it is not trigging the job. No errors of any kind in my log however.

    I don't know even know where to begin with this thing. Any help is much appreciated.

  • #2
    One step further...

    Found a few clues to my own problem:

    The problem starts here, because the trigger is not a SimpleTrigger but an instance of Spring Frameworks SimpleTriggerBean.

    This is code snipped from
    JobStoreSupport - storeTrigger(SchedulingContext, Trigger, boolean):


    if (existingTrigger) {
    if (newTrigger.getClass() == SimpleTrigger.class) {
    getDelegate().updateSimpleTrigger(conn,
    (SimpleTrigger) newTrigger);
    } else if (newTrigger.getClass() == CronTrigger.class) {
    getDelegate().updateCronTrigger(conn,
    (CronTrigger) newTrigger);
    } else {
    getDelegate().updateBlobTrigger(conn, newTrigger);
    }
    getDelegate().updateTrigger(conn, newTrigger, state, job);
    }

    This means that the jobStore treats the trigger as a blob and tries to store it as such:

    This throws an exception in the WebLogicOracleDelegate class:

    java.io.NotSerializableException: org.springframework.context.support.ClassPathXmlAp plicationContext.

    If I'm doing something wrong I'd appreciate the feedback, otherwise thsi looks like a bug...

    Comment


    • #3
      I could be way off the mark here, but I don't see how this is ever going to work. SimpleTriggerBean has a JobDetailBean, JobDetailBean has an ApplicationContext and as far as I know its not Serializable. JobDetailBean also stuffs one in the jobDataMap.

      I would presume (again could be way off the mark), you aren't supposed to allow these to be persistent. If you JobDetailBean is persistent and a Spring singleton, does it really make sense to store it in the database. Restart the server and hey presto, Spring configures the JobDetailBean and we have another in the database. Not very singleton.

      Can anyone clarify this issue? It seems theres something lacking here, either something we're missing, documentation missing or code to prevent you making them persistent. Might even be all of the above.
      Last edited by karldmoore; Nov 25th, 2006, 11:02 AM.

      Comment


      • #4
        Continued... ProSpring caught with trousers down.

        Yes. You're right on this. This is just not meant to work for persistent jobs. I wish the documentation could have spelled this out more clearly.

        I'll give an update on the issue when I have a finished solution.

        It's interesting that the book ProSpring (p. 513) , shows this almost identical config as an example of how to use persistent jobs(!) I guess they just didn't test it properly. Shame on you, guys.

        Comment


        • #5
          Originally posted by superpuma View Post
          Yes. You're right on this. This is just not meant to work for persistent jobs. I wish the documentation could have spelled this out more clearly.

          I'll give an update on the issue when I have a finished solution.

          It's interesting that the book ProSpring (p. 513) , shows this almost identical config as an example of how to use persistent jobs(!) I guess they just didn't test it properly. Shame on you, guys.
          As I said before, I wasn't sure this was the case it just didn't feel right. I do think though this should be raised in the JIRA, the documentation doesn't spell this out and its very confusing. Let me know if you plan to raise this, otherwise I'll do it. Might also be worth raising this as in issue on the publishers site.

          Comment


          • #6
            I back karldmoore posts - if the docs are unclear please raise an issue on jira (it takes a couple of minutes registration included). We are keen on improving the docs but we can't fix bugs which we don't know about.
            Thanks!

            Comment


            • #7
              I'll check JIRA at the end of today, if it hasn't been raised I'll raise it myself.

              Comment


              • #8
                Registered the issue

                OK. I registered the issue on JIRA. This is my description (below). Please comment if you have anything to add.

                http://opensource.atlassian.com/proj...rowse/SPR-2877

                This is mainly a documentation issue. (Although it would be possible to improve on the design as well)

                The problem is the org.springframework.scheduling.quartz.JobDetailBea n. It should be clearly stated that this bean cannot be used with a persistent job store. This is such an important issue when using Quartz, that it should be mentioned explicitly. Among other things, a persistent job store is required when running Quartz in a cluster. This is a very common requirement in enterprise applications, and JobDetailBean is therefore not very useful for most applications.

                My problem actually stems from using code copied from the book ProSpring (p 513) by Rob Harrop, where he shows an example of using JobDetailBean with a persistent job store. Clearly, this config has never been tested. This is a widely read book (by an Interface21 guy AFAIK), and this config will be widely read and copied.

                In my opinion the code could be improved:
                The problem stems from JobDetail bean being ApplicationContextAware, which it needn't be. (It puts the applicationContext in the jobDataMap) SchedulerFactory puts the applicationContext in the schedulerContext anyway, why can not the Job get the applicationContext from there?

                See this thread for some further info:
                http://forum.springframework.org/showthread.php?t=31820

                Comment


                • #9
                  And here is a solution.

                  I used the JobDetail bean directly, to avoid the serialization issue. The config is a bit longer, but ot does the trick.

                  <bean name="updateDailyRatesJob" class="org.quartz.JobDetail">
                  <property name="jobClass">
                  <value>
                  jobs.quartz.DailyUpdateJob
                  </value>
                  </property>
                  <property name="name">
                  <value>updateDailyRatesJob</value>
                  </property>
                  <property name="jobDataMap">
                  <bean class="org.quartz.JobDataMap">
                  <constructor-arg>
                  <map>
                  <entry key="message">
                  <value>Some message</value>
                  </entry>
                  </map>
                  </constructor-arg>
                  </bean>
                  </property>
                  </bean>

                  And here is the job:

                  public class DailyUpdateJob extends QuartzJobBean {

                  private Log log = Log.getInstance(DailyUpdateJob.class.getName());



                  /**
                  * @param context
                  * @throws JobExecutionException
                  */
                  protected void executeInternal(JobExecutionContext context) throws JobExecutionException {

                  log.error(new LogMessage("EXECUTE", "EXECUTE JOB!!!!!!!!!!!!!"));

                  // throw new JobExecutionException();

                  }
                  }

                  Using the QuartzJobBean I can pull everything out of the SchedulerContext, or rather it will be injected on the bean, if I just provide the setters and setup the SchedulerContext on SchedulerFactoryBean.

                  I honestly don't understand the JobDetailBean, though. Why does it need to be ApplicationContextAware. Can't seem to provide any benefits from this...

                  Comment


                  • #10
                    One thing to think about with regards to your new bean is scope. Should it be default (singleton) or prototype?

                    Regarding the ApplicationContextAware issue, I would assume this is just so there is supplied access to the ApplicationContext.

                    Comment


                    • #11
                      Quartz 1.6 and the ProSpring example

                      Seems that the Quartz code changed from version 1.5.2 in such a way that the config no longer works.

                      So, let me retract any slanderous remarks about the ProSpring book.:-)

                      I guess the ProSpring example did work at the time it was written.

                      On the issue of whether thye bean should be a prototype or singleton, I don't know. If you any thoughts on that let me know. Are there any GC issues surrounding this that I should be aware of?

                      Comment


                      • #12
                        Originally posted by superpuma View Post
                        Seems that the Quartz code changed from version 1.5.2 in such a way that the config no longer works.

                        So, let me retract any slanderous remarks about the ProSpring book.:-)

                        I guess the ProSpring example did work at the time it was written.

                        On the issue of whether thye bean should be a prototype or singleton, I don't know. If you any thoughts on that let me know. Are there any GC issues surrounding this that I should be aware of?
                        Might want to add that information to the JIRA issue you raised, quite useful.

                        Just conceptually if you ask for the bean several times, I would have thought that you would want different instances. If reuse the same Job you might have to start thinking about threading as there might be common state. I would have thought that prototype might make more sense.

                        Comment


                        • #13
                          Originally posted by karldmoore View Post
                          Might want to add that information to the JIRA issue you raised, quite useful.

                          Just conceptually if you ask for the bean several times, I would have thought that you would want different instances. If reuse the same Job you might have to start thinking about threading as there might be common state. I would have thought that prototype might make more sense.
                          I'm having similiar issues with the JDBCJobStore. I tried using the example that was posted earlier in the thread that used the direct quartz jobbean configuration, but I still get a not serializable error. I'm trying to inject one of my services into the job bean for the job bean to call. What I don't understand is how this would ever work without making one's entire service layer serializable. Am I missing something? Is there a different approach to satisfying the JobBeans dependencies that I should be taking? Have you guys found anything else that might help?

                          Comment


                          • #14
                            Well that was exactly my point........ how could it ever work?

                            I could be way off the mark here, but I don't see how this is ever going to work. SimpleTriggerBean has a JobDetailBean, JobDetailBean has an ApplicationContext and as far as I know its not Serializable. JobDetailBean also stuffs one in the jobDataMap.
                            I would have thought that that serialized jobs should maybe just contain the data. When the job executes it can lookup the service it requires and do the work.

                            Comment


                            • #15
                              Originally posted by karldmoore View Post
                              Well that was exactly my point........ how could it ever work?



                              I would have thought that that serialized jobs should maybe just contain the data. When the job executes it can lookup the service it requires and do the work.
                              That is exactly the service I would expect the Spring JobDetail bean to provide. Dependency injection at job execution time. I'm not sure how they'd implement that though. Is there any sort of working example of Spring and the Quartz JDBCJobstore that includes a dependency between the job and some other spring managed bean?

                              Comment

                              Working...
                              X