i have a spring batch job which needs to be scheduled at specific hour of the day. I have setup a Quartz CRON scheduler to accomplish this. However i see that the job is getting triggered only once.
What could be wrong ?
following is the XML file snippet -
<batch:job id="getFleetUpdatesJob" job-repository="jobRepository">
<batch:step id="step0">
<batch:tasklet ref="fleetUpdatesID" transaction-manager="jobRepository-transactionManager" />
</batch:step>
<!-- <batch:step id="step1" next="step2">
<batch:tasklet ref="world" transaction-manager="jobRepository-transactionManager" />
</batch:step> -->
</batch:job>
<!-- Quartz related beans START -->
<bean name="updateDataFeedJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="<package>.schedule.UpdateDataFeedJob" />
</bean>
<bean id="cronTriggerId" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="updateDataFeedJobDetail" />
<!-- run every morning at 3AM -->
<!-- <property name="cronExpression" value="0 0 3 * * ?" /> -->
<!-- run the job at 8pm everyday -->
<property name="cronExpression" value="0 0 20 * * ?" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTriggerId" />
</list>
</property>
</bean>
<!-- Quartz related beans END -->
I suspect the cron expression is working correctly, however a Spring Batch job will only execute once unless it's parameters change.
You can verify this if you get a stack trace similar to:
2011-08-18 00:40:26,155 INFO [org.springframework.batch.core.launch.support.SimpleJobLauncher] - <Job: [FlowJob: [name=job1]] completed with the following parameters: [{run.id=1}] and the following status: [COMPLETED]>
2011-08-18 00:40:30,002 INFO [com.beny23.test.JobLauncherDetails] - <Quartz trigger firing with Spring Batch jobName=job1>
2011-08-18 00:40:30,015 ERROR [com.beny23.test.JobLauncherDetails] - <Could not execute job.>
org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={run.id=1}. If you want to run this job again, change the parameters.
at org.springframework.batch.core.repository.support.SimpleJobRepository.createJobExecution(SimpleJobRepository.java:122)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
In order to ensure that the parameters for each job invokation are different, you could modify the UpdateDataFeedJob class to call your job like this:
JobParametersBuilder builder = new JobParametersBuilder();
builder.addLong("run.ts", System.currentTimeMillis());
JobParameters jobParameters = builder.toJobParameters();
Job job = jobLocator.getJob(jobName);
jobLauncher.run(job, jobParameters);
I dont now spring but i use Quartz .I think problem is ,you are giving two cron expression.You must give a single cron expression like 0 0 3-20 * * ? (some thing like that ) ,crontrigger can have only one cron expression rewrite cron expression that fire at 3 and 20 .
Related
I'm following this tutorial to schedule jobs with Spring.
In the tutorial scheduling is started by the following code:
public static void main(String args[]){
AbstractApplicationContext context = new ClassPathXmlApplicationContext("app-config.xml");
}
Instead of using main, i'd like to start jobs with a method that can be called from anywhere in my application, for example:
public void startJobs() {
// what should this method do to start the jobs?
}
Can the following work?
public void startJobs() {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("app-config.xml");
}
Is this considered good practice?
Basically what i want to achieve is to be able to start the jobs whenever i want (whenever i call the startJobs() method), not on startup in the main method.
How can i do this?
Have you done with scheduling using quartz and spring. If yes, is it running fine? The example link you shared belongs to "The Task Namespace"
Quartz uses Trigger, Job and JobDetail objects to realize scheduling of all kinds of jobs. For the basic concepts behind Quartz, have a look at
http://quartz-scheduler.org/documentation/quartz-2.2.x/quick-start
To integrate it with Spring, Please have a look at this also
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html#scheduling-quartz-jobdetail
XML Configuration of Spring and quartz.
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<bean
class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor">
<property name="jobRegistry" ref="jobRegistry" />
</bean>
<bean id="jobRegistry"
class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
<bean name="csvLoaderJobDetail"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.example.CSVloader.ScheduledJob" />
<property name="jobDataMap">
<map>
<entry key="csvData" value="value1" />
<entry key="date" value="25/09/2015" />
<entry key="csvId" value="1" />
<entry key="jobName" value="csvLoadJob" />
<entry key="jobLocator" value-ref="jobRegistry" />
<entry key="jobLauncher" value-ref="jobLauncher" />
</map>
</property>
<property name="durability" value="true" />
</bean>
<bean id="csvLoaderTrigger"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="csvLoaderJobDetail" />
<property name="cronExpression" value="0 0 12 * * ?" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="csvLoaderJobDetail" />
</list>
</property>
<property name="triggers">
<list>
<ref bean="csvLoaderTrigger" />
</list>
</property>
<property name="quartzProperties">
<props>
<prop key="org.quartz.scheduler.skipUpdateCheck">true</prop>
</props>
</property>
</bean>
To fire the job manually, you need to inject SchedulerFactoryBean in your spring bean. First you need to get all the jobs created in quartz scheduler, then you can trigger any job manually by using Job Key and Job group of each job.
#Autowired
private SchedulerFactoryBean schedulerFactory;
org.quartz.Scheduler scheduler = schedulerFactory.getScheduler();
// loop jobs by group
for (String groupName : scheduler.getJobGroupNames()) {
// get jobkey
for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher
.jobGroupEquals(groupName))) {
String jobName = jobKey.getName();
String jobGroup = jobKey.getGroup();
scheduler.triggerJob(jobName, jobGroup);
}
}
Now you can create a list of Object, which contain jobName and jobGroup to trigger any job manually.
A better and easy way , use #Scheduled annotation.
Method 1) Task scheduling using fixed delay attribute in #Scheduled annotation
#Scheduled(fixedDelay = 5000)
Method 2) Task scheduling using cron expression in #Scheduled annotation
#Scheduled(cron="*/5 * * * * ?")
Method 3) Task scheduling using cron expression from properties file
#Scheduled(cron = "${cron.expression}")
You can get complete example here
I'm using quartz scheduler for scheduling a spring batch job.
The application starts without any exception but it never fires any job.
Just let me to explain my scenario:
If I run the job(with scheduler) through a main method using MapJobRepositoryFactoryBean it works perfectly, but after integration of the scheduler with spring-mvc web app it shows some version update error, after that I used "JobRepositoryFactoryBean" which uses database for storing job states.
So I added JobRepositoryFactoryBean bean and other DB changes, but it never triggers the job.
bellow is a snippet of log
2015-02-10 19:14:45 INFO context.support.XmlWebApplicationContext - Bean 'jobRegistry' of type [class org.springframework.batch.core.configuration.support.MapJobRegistry] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2015-02-10 19:14:45 INFO jdbc.datasource.DriverManagerDataSource - Loaded JDBC driver: com.mysql.jdbc.Driver
2015-02-10 19:14:45 INFO launch.support.SimpleJobLauncher - No TaskExecutor has been set, defaulting to synchronous executor.
2015-02-10 19:14:46 INFO context.support.DefaultLifecycleProcessor - Starting beans in phase 2147483647
2015-02-10 19:14:46 INFO scheduling.quartz.SchedulerFactoryBean - Starting Quartz Scheduler now
2015-02-10 19:14:46 INFO web.servlet.DispatcherServlet - FrameworkServlet 'mvc-dispatcher': initialization completed in 2155 ms
Here is my job configuration
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<bean
class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor">
<property name="jobRegistry" ref="jobRegistry" />
</bean>
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"
p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager">
<property name="databaseType" value="reconConfig!{batch.databaseType}" />
<property name="isolationLevelForCreate" value="ISOLATION_DEFAULT" />
</bean>
<bean id="mapJobRepository"
class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"
lazy-init="true" autowire-candidate="false" />
<bean id="jobOperator"
class="org.springframework.batch.core.launch.support.SimpleJobOperator"
p:jobLauncher-ref="jobLauncher" p:jobExplorer-ref="jobExplorer"
p:jobRepository-ref="jobRepository" p:jobRegistry-ref="jobRegistry" />
<bean id="jobExplorer"
class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean"
p:dataSource-ref="dataSource" />
<bean id="jobRegistry"
class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="appDataSource" />
</bean>
<bean class="org.springframework.batch.core.scope.StepScope" />
<bean id="reconConfigPlaceholderProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="location" value="classpath:batchDb.properties" />
<property name="placeholderPrefix" value="reconConfig!{" />
<property name="placeholderSuffix" value="}" />
</bean>
</beans>
It was running successfully , but after some more development it stopped working. I'm unable to figure out what exactly I changed in configuration which caused this.
Can any one please suggest the check points in using "JobRepositoryFactoryBean", If I'm missing or the problem is else where.
If this is your entire configuration for job scheduling, I believe you are missing the Cron scheduling part entirely...
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="jobDetail" />
<property name="cronExpression" value="*/10 * * * * ?" />
</bean>
</property>
</bean>
Please read through the spring doc and the quartz scheduling section here.
We have had the similar or the same problem. Look into DB repository. Repository is not resistant from different instances of application server (e.g. testing and development environment). It means, when two or more applications are connected into the same DB, you can have a problem. Applications begin to pull on the time and jobs. Unregistered jobs in one application are signed as ERROR and blocked and vice versa.
Two tables are important in this case.
Select XXX_SCHEDULER_STATE. Is there more than one row? Than there can be conflict. (Are you not able to distinguish your APP Server? If yes, you are connected into another DB than you suppose. It is very often but trivial problem.)
Select XXX_TRIGGERS.TRIGGER_STATE is there ERROR? If yes, try to change it from any SQL tool:
update TRIGGERS set TRIGGER_STATE = 'WATING' where TRIGGER_STATE = 'ERROR';
Restart application server. If you have a luck, the failed trigger started and work after restart. If not, try to shutdown concurrent App Server or change the repository.
I am using spring scheduler tasks for calling a method in class after fixed interval like below
<task:scheduled-tasks scheduler="scheduler">
<task:scheduled ref="processScheduledJobs" method="init" fixed-delay=5000/>
Once the scheduler triggers the init method. init method is going to use the thread pool executor to execute all the jobs in the queue.
<bean id="processScheduledJobs" class="XXXX.VV.ProcessScheduledJobs">
<property name="pool" ref="jobExecutorService"" />
</bean>
<bean id="scheduler" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="threadFactory">
<bean class="XXX..VVV.NamingThreadFactory">
<constructor-arg value="thread" />
</bean>
</property>
<property name="corePoolSize" value="16" />
<property name="maxPoolSize" value="64" />
<property name="keepAliveSeconds" value="4" />
<property name="queueCapacity" value="512" />
</bean>
Questions:
is the initial thread which executed the init method wait till all the processing (done by executor service by spawning new threads) in the init method is finished?
Is the pool size attribute for scheduler task is only used for triggering the tasks not for executing or processing the logic inside the triggered task.
Thread belonging to scheduler will submit all jobs to jobExecutorService. Up to 64 of them will begin executing immediately, the rest, up to 512 will end up in queue. As soon as all are submitted - not executed - the init method will exit. This shouldn't take longer than mere milliseconds.
If scheduler is not the same as jobExecutorService - I can't tell this since part of your xml is missing - its threads won't be used for execution of jobs logic.
I implemented a Scheduled Job in Spring, I'm using Spring 3.1.1 with Hibernate and Struts2. The configuration works fine, but I want to change de cron dynamically, so I found several examples but I could not implement them, everywhere are different configurations, I only need to read cron values from the database instead of configuration file. Is this possible somehow?
My configuration now looks like that:
<!-- Scheduler Tasks -->
<bean name="statTask" class="com.bvc.spring.schedulers.MarketStatusJob"></bean>
<!-- Scheduler jobs -->
<bean id="statJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="statTask" />
<property name="targetMethod" value="execute" />
</bean>
<!-- Cron Triggers -->
<bean id="statCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="statJobDetail" />
<property name="cronExpression" value="0 30 12 1/1 * ? *"/>
</bean>
<!-- Triggers -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="statCronTrigger"/>
</list>
</property>
</bean>
Thanks in advance for help guys.
The possibly easiest approach would be, to subclass CronTriggerBean and implement database property resolution in an overridden setCronExpression(..) method, where you go to the database, fetch the desired cron, and call super.setCronExpression(dbValue)
An alternative, harder approach is to implement a PropertyPlaceholderConfigurer that reads them from a database rather than a properties file. It may not be trivial, though. There is no support for that, because it is more customary to read the values from a properties file. Also note that you won't be able to change the cron dynamically during execution.
You dont need to have statCronTrigger, need to implement quartz trigger in your main class
Job detail is fine.
CronTrigger trigger = null;
JobDetail jobD;
//Load context
ApplicationContext context = new ClassPathXmlApplicationContext("YOUR_CONTEXT_FILES.xml");
//Setup JobDetail
jobD = (JobDetail) context.getBean("statJobDetail");
//Setup CronTrigger
try {
trigger = new CronTrigger();
trigger.setName("AppTrigger");
trigger.setGroup(jobD.getGroup());
trigger.setJobName(jobD.getName());
trigger.setJobGroup(jobD.getGroup());
trigger.setCronExpression("*/10 * * * * ?");// you can read this from DB as well or any other configured string
} catch (ParseException e1) {
e1.printStackTrace();
}
//Scheduler
try{
Scheduler scheduler = (Scheduler) context.getBean("Scheduler");
scheduler.scheduleJob(jobD, trigger);
You may add quartz scheduler bean in context
<bean id="Scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"></bean>
I am currently using quartz schedular which comes with spring framework.Our requirement is to schedule a method on daily basis which will call a webservice(only one method on the webservice).My configuration is as below.
<bean id="downloadJob"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="adapter" />
<property name="targetMethod" value="getData" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="downloadJob" />
</list>
</property>
<property name="triggers">
<list>
<ref bean="cronTrigger" />
</list>
</property>
</bean>
<bean id="cronTrigger"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="downloadJob" />
<property name="cronExpression" value="" />
</bean>
I am reading the cronExpression value from properties file.
Please provide me some pointers to implement the schedular in better way. i have seen in some other projects where only using quartz with out spring.They are taking care of thread pool and some other properties as below.I am first time working on schedular implementation.Please provide me some suggestions/pointers on how to take care of these below properties while using quartz with spring(org.springframework.scheduling.quartz.SchedulerFactoryBean).Please suggest me if i need to take care of anyother things apart from these.
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 15
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
That's a fine way to implement a scheduler in Spring. The Spring reference has a whole section on Quartz integration that should help get you started. For setting Quartz properties, use the SchedulerFactoryBean's quartzProperties property. You'll have to decide yourself if there's anything else to take care of by reading up on Quartz in general and learning more about Quartz configuration.