How do we add startTime in springframework.scheduling.quartz.CronTriggerFactoryBean? - spring

We need to add the startTime for spring quartz scheduler. Lets assume the below bean as CronTriggerFactoryBean. And we need to start the scheduler after 5 days of server starting time.
<bean id="sampleBean"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail">
<bean class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="beanManager"/>
<property name="targetMethod" value="beanMethod"/>
<property name="concurrent" value="false"/>
</bean>
</property>
<property name="cronExpression" value="0 0/30 * ? * SUN-FRI"/>
</bean>
And above scheduler configuration doesn't start when application server get started. Its running like
Let's assume server start at 12:03 PM.
Scheduler invoking at 12:30, 13:00, 13:30, 14:00 ... respectively.
But what we want is server start at 12:03 PM means the scheduler should run once at the time of server starting and the following time too 12:33, 13:03, 13:33, 14:03 ...
Will it work when we are setting the startTime for this bean?

You should use SimpleTriggerFactoryBean instead of CronTriggerFactoryBean and define a trigger like this:
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="simpleJobDetail" />
<property name="startDelay" value="1000" />
<property name="repeatInterval" value="10000" />
</bean>
This will run the job every 10 seconds with initial delay of 1 second from server start. Now adjust the values as per your requirements.

Related

Quartz cluster - load balancing doesn't work

I have a problem with load-balancing Quartz jobs. When there are two instances running, only one of them handles all jobs. The second one is idling. When I terminate first instance the second one starts to handle jobs until first instance is started again.
I expected that there is kind of load-balancing which dispatches jobs between those two instances.
I am using Quartz version 1.8.6.
This is the part of applicationContext.xml:
<bean id="firstJobDetail"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.mycompany.quartz.job.FirstJob" />
<property name="durability" value="true" />
</bean>
<bean id="firstTrigger" class="com.mycompany.quartz.PersistableCronTriggerFactoryBean">
<property name="jobDetail" ref="firstJobDetail" />
<property name="cronExpression" value="0/10 * * * * ?" />
</bean>
<bean id="quartzScheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="configLocation" value="classpath:META-INF/quartz.properties" />
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
<!-- This name is persisted as SCHED_NAME in db. for local testing could
change to unique name to avoid collision with dev server -->
<property name="schedulerName" value="quartzScheduler" />
<!-- Will update database cron triggers to what is in this jobs file on
each deploy. Replaces all previous trigger and job data that was in the database.
YMMV -->
<property name="overwriteExistingJobs" value="true" />
<property name="autoStartup" value="true" />
<property name="applicationContextSchedulerContextKey" value="applicationContext" />
<property name="jobFactory">
<bean class="com.mycompany.quartz.AutowiringSpringBeanJobFactory" />
</property>
<!-- NOTE: Must add both the jobDetail and trigger to the scheduler! -->
<property name="jobDetails">
<list>
<ref bean="firstJobDetail" />
</list>
</property>
<property name="triggers">
<list>
<ref bean="firstTrigger" />
</list>
</property>
</bean>
And this is the quartz.properties file:
# Spring uses LocalDataSourceJobStore extension of JobStoreCMT
org.quartz.jobStore.useProperties=true
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
# Change this to match your DB vendor
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# Needed to manage cluster instances
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.instanceName=MY_JOB_SCHEDULER
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
According to the documentation, you need to set org.quartz.jobStore.clusterCheckinInterval .
I Know it is too late to answer your question. But recently I come across the same issue and found your post in online.
Whenever there are two instances running, either one of them tries to put lock on the job. Since your trigger time is every 10 secs which is very less (0/10 * * * * ?), the instance 2 is unable to put lock on the job.
Increase the time period to one minute(* 0/1 * * * ?). You can see, both the instance will process the job.
Please let me know if you face any other issues.
Documentation says:
Load-balancing occurs automatically, with each node of the cluster
firing jobs as quickly as it can. [...] Only one node will fire the
job for each firing. [...] It won’t necessarily be the same node each
time - it will more or less be random which node runs it. The load
balancing mechanism is near-random for busy schedulers (lots of
triggers) but favors the same node for non-busy (e.g. few triggers)
schedulers.

Creating multiple SchedulerFactoryBean in Quartz

I have run into a problem where I have two classes extending QuartzJobBean. The problem I am facing is to create two SchedulerFactoryBean. I did my research and found that setting the property schedulerName solves the problem. This did not work for me. I used #Qualifier also. If I create the two beans of SchedulerFactoryBean , Spring doesn't know which scheduler to refer to. I have two CronTriggers.
Code:
<!--
<bean name="quartzSchedulerR" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="com.task.QuartzScheduler" />
<property name="jobDataAsMap">
<map>
<entry key="rRSImpl" value-ref="rRSService" />
<entry key="SRObject" value-ref="SRObject"/>
</map>
</property>
</bean>
<bean id="cronTriggerR"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="quartzSchedulerR" />
<property name="cronExpression" value="0 30 12 ? * MON *" />
</bean>
<bean id="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false">
<property name="schedulerName" value="scheduleOne"/>
<property name="schedulerContextAsMap">
<map>
<entry key="rSchedulerServiceImpl" value-ref="rSchedulerServiceImpl"></entry>
</map>
</property>
<property name="jobDetails">
<list>
<ref bean="quartzSchedulerR" />
</list>
</property>
<property name="triggers">
<list>
<ref bean="cronTriggerR" />
</list>
</property>
</bean> -->
<bean id ="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false">
<property name="schedulerContextAsMap">
<map>
<entry key="rSSImpl" value-ref="rSSImpl"></entry>
</map>
</property>
</bean>
<bean id="jobDetailFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName">
<idref local="jobDetail" />
</property>
</bean>
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailBean" scope="prototype">
<property name="jobClass" value="com.scheduler.SMTPMailJob " />
<property name="jobDataAsMap">
<map>
<entry key="rSSeImpl" value-ref="rSSImpl" />
<entry key="fUtil" value-ref="fUtil" />
<entry key="rService" value-ref="rService" />
<entry key="fusion" value-ref="fusion"/>
<entry key="fcproperties" value-ref="fcproperties"/>
</map>
</property>
</bean>
<bean id="jobTriggerFactory"
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName">
<idref local="jobTrigger" />
</property>
</bean>
<bean id="jobTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"
scope="prototype">
</bean>
Currently I comment out the first scheduler and the application works as expected. But if I uncomment it, the second scheduler stops working. Any workaround for this issue.. ? Any help is appreciated.
EDIT: There is no error but I know that the job isn't scheduled. The error is basically that spring doesn't find a unique bean for com.quartz.Scheduler when both the SchedulerFactoryBean are defined. Basically how to configure multiple SchedulerFactoryBean for totally isolated classes.. ?
Please can you explain why do you need two scheduarfactorybeans.
As per spring doc, FactoryBean that creates and configures a Quartz Scheduler, manages its lifecycle as part of the Spring application context, and exposes the Scheduler as bean reference for dependency injection.
This means you cant have multiple instances of the bean.
Also as per your code you are trying to schedule multiple jobs which can be done using one schedularFactoryBean. Create Multiple job beans and their corresponding triggers and add them as list to the schedular factoryBean. All the triggers will be invoked as per configuration irrespective of whether it is a cron trigger or simple trigger.

How to force beans in quartz scheduler to be initialized on start up?

<bean name="MyJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.package.scheduler.MyJob"/>
<property name="jobDataAsMap">
<map>
<entry key="numArr" value="10,20,30"/>
</map>
</property>
</bean>
I have a quartz job defined that runs this at 1:30am. The problem is this array definition does not work
<entry key="numArr" value="10,20,30"/>
We had to use list instead. Since the beans do not get initialized until the quartz job kicks in and it's unlikely we would be coding at 1:30am, we cannot catch this error locally. The only way right now is to change the quartz job's running time to force it to happen. We want to force these beans to be initialized on startup when we are running on local dev. Is there a way to do this?
If possible I would decouple your bean from the Quartz job. You could then intialise your bean separately in your spring configuration and it does not need to be made aware of Quartz. I would then use the spring MethodInvokingJobDetailFactoryBean to call a method on your decoupled object.
For example something similar to this:
<bean id="myBean class="...">
<property name="numArr" value="10,20,30"/>
</bean>
<bean id="myJob"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myBean" />
<property name="targetMethod" value="doSomething" />
</bean>
<bean id="staleTraderRatesTrigger"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="myJob" />
<property name="cronExpression" value="0 30 1 * * ?" />
</bean>

quartz jobs in a cluster running on wrong node

uI have an application that is clustered in a 2+2 setup where 2 machines are used in alpha product phase, and the other two are used for real customers. all machines are looking at the same database,
I need a job to run at midnight for each of the groups. one of the two alpha machines should get a job, and the other two should get another job.
I'm using Spring 3.0.5 with Quartz 1.8.5 with the following properties
phase=alpha
quartz.job.name=MY_JOB_${phase}
<bean id="quartzPropertiesFactoryBean" class="com.liveperson.kwo.quartz.QuartzPropertiesFactory">
<constructor-arg value="AUTO"/>
<constructor-arg value="MY_CLUSTER"/>
<constructor-arg value="JobStoreTX"/>
<constructor-arg value="StdJDBCDelegate"/>
<constructor-arg value="true"/> //isClustered
<constructor-arg value="false"/> //useProperties
</bean>
<bean name="runJobBean" class="org.quartz.JobDetail">
<property name="name" value="${quartz.job.name}"/>
<property name="jobClass" value="CLASS1"/>
<property name="group" value="JOB-for-${quartz.job.name}"/>
<property name="jobDataMap">
<bean class="org.quartz.JobDataMap">
</bean>
</property>
</bean>
<bean name="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="quartzProperties" ref="quartzPropertiesFactoryBean"/>
<property name="dataSource" ref="mySqlConnectorBean"/>
<property name="overwriteExistingJobs" value="true"/>
<property name="jobDetails">
<list>
<ref bean="runJobBean"/>
</list>
</property>
<property name="triggers">
<list>
<ref bean="cronTriggerBean"/>
</list>
</property>
</bean>
I define two jobs, one for alpha and another for production throw the phase property, and the problem I'm having is that the job I define for alpha phase runs on the node defined to production, how can I make the job defined for the alpha phase run only on machines defined for alpha?
Thanks!

Spring Quartz Scheduling

In my application there is a requirement to be able to create Scheduled Job(s) for My sql database autobackup
Can I use Spring Quartz Scheduling to create this Jobs?
Any help would be useful.
Amulraj.P
Yes you can, though it seems a bit overkill. Backuping an MSSQL db can be done using commandline tools, which you can easily schedule to run using cron if you are using Unix or Scheduled Tasks on Windows.
%PATH_TO_SQL_SERVER%\Tools\Binn\osql.exe
-E -Q "BACKUP DATABASE mydb TO DISK='%PATH_TO_BKP%\db.bak' WITH FORMAT"
For you question the answer is something like this: (shameless self-copy from here)
The job referring to your business object which has the method which takes care of the backup:
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="exampleBusinessObject" />
<property name="targetMethod" value="backupDB" />
<property name="concurrent" value="false" />
</bean>
The trigger that takes care of firing the method:
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="exampleJob" />
<!-- run every morning at 6 AM, use regular cron expressions-->
<property name="cronExpression" value="0 0 6 * * ?" />
</bean>
The schedulerFactoryBean for wiring the trigger:
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger" />
</list>
</property>
</bean>
See further in Spring documentation for 2.5, here for 3.0.

Resources