Java – Scheduled jobs with Quartz scheduler with default values

javaquartz-schedulerspring

We have a web application running in Tomcat using Spring Framework. We need to add some scheduled jobs for recurrent operations. We came across Quartz Scheduler for this and followed a tutorial for configuring Jobs using Quartz with Spring and got the jobs scheduled and running as expected.

So we have some tasks that are scheduled when the application starts. Now we want the user to manually run the jobs and change the trigger for the jobs, but we need that these changes are persisted to database. So when the application starts, it would read the persisted tasks and if they don't exist, load the default tasks from the spring descriptor file.

For simplicity's shake, let's assume that we're using the beans.xml file from the example:

<bean id="processToExecute" class="com.mycompany.ProcessToExecute" />

<bean name="processToExecuteJob" class="org.springframework.scheduling.quartz.JobDetailBean">
    <property name="jobClass" value="com.mycompany.ProcessToExecuteJob" />
    <property name="jobDataAsMap">
        <map>
            <entry key="processToExecute" value-ref="processToExecute" />
        </map>
    </property>
</bean>

<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
    <property name="jobDetail" ref="processToExecuteJob" />
    <property name="cronExpression" value="0/5 * * * * ?" />
</bean>

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="jobDetails">
        <list>
            <ref bean="processToExecuteJob" />
        </list>
    </property>
    <property name="triggers">
        <list>
            <ref bean="simpleTrigger" />
        </list>
    </property>
</bean>

So we'd like to continue using beans-like configuration for default tasks but the option to load them from database if already scheduled.

Quartz here is not a requirement, if anyone knows a easier way to achieve it using Spring @Scheduled it could be useful too.

Thanks for your time.

Best Answer

I finally struggled to obtain the desired behavior. On the first run, the application schedules the task and persist them to database. This is done simply by specifying the dataSource property on the SchedulerFactoryBean object.

At this time, persisting the jobs is useless because any change performed to the scheduled tasks is lost when the system restarts, because newly created jobs overwrite the old ones. So the behavior is exactly the same.

To avoid new jobs to overwrite old ones, simply set the overwriteExistingJobs property to false on the SchedulerFactoryBean object. As simple as that. New jobs are ignored because they already exists in the database.

This is the complete example for the configuration described above:

<!-- Jobs -->
<bean name="processToExecuteJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <!-- JobDetailBean on Quartz 1.X -->
    <property name="jobClass" value="com.mycompany.quartz.ProcessToExecuteJob" />
    <property name="name" value="processToExecuteJob"/>
    <property name="group" value="default"/>
</bean>


<!-- Triggers -->
<bean id="demoTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <!-- CronTriggerBean on Quartz 1.X -->
    <property name="jobDetail" ref="processToExecuteJob" />
    <property name="cronExpression" value="0/15 * * * * ?" />
</bean>


<!-- Database -->
<jee:jndi-lookup id="quartzDataSource" jndi-name="jdbc/imsQuartzDS" resource-ref="true" />


<!-- Scheduler -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="dataSource" ref="quartzDataSource"/>
    <property name="overwriteExistingJobs" value="false"/>
    <property name="triggers">
        <list>
            <ref bean="demoTrigger" />
        </list>
    </property>
</bean>
Related Topic