The similar questions seem to be asked many times,but I still can't find the exact answer.I use org.quartz.StatefulJob to setup a scheduled job to retry it for 5 times by simulating an Exception and Spring cron to trigger it, but some exception occurred,here's the details:
@Service(value = "cronJobRetryImpl")
public class DuMiSynchronizationRetryRest implements StatefulJob {
private Logger logger = Logger.getLogger(getClass());
@Override
public void execute(JobExecutionContext context) throws
JobExecutionException {
logger.info("enter execute ...");
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
long count =
NumberUtils.toLong(String.valueOf(dataMap.get("count")));
if (count >= 5) {
logger.info("Retries exceeded...");
JobExecutionException e = new JobExecutionException("Retries
exceeded");
e.setUnscheduleAllTriggers(true);
throw e;
}
try {
logger.info("business begin...");
dataMap.put("count", 0);
int n = 10 / 0;
} catch (Exception e) {
count++;
dataMap.putAsString("count", count);
JobExecutionException e2 = new JobExecutionException(e);
try {
logger.info("Thread begin to sleep for 3 seconds...");
Thread.sleep(3000);
} catch (InterruptedException e1) {
logger.info("interrupted exception",e1);
}
e2.refireImmediately();
logger.info("job refired ...");
throw e2;
}
}
}
Here's the Spring xml:
<!-- retry test start -->
<bean id="cronJobRetryImplTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" lazy-init="true">
<property name="targetObject">
<ref bean="cronJobRetryImpl" />
</property>
<property name="targetMethod">
<value>execute</value>
</property>
<property name="concurrent" value="false" />
</bean>
<bean id="cronJobRetryTime" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref bean="cronJobRetryImplTask" />
</property>
<property name="cronExpression">
<value>20 30 9 * * ?</value>
</property>
</bean>
<!-- retry test end -->
<bean id="startQuertz" lazy-init="false" autowire="no"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronJobRetryTime" />
</list>
</property>
I planned to trigger it on every 9:30:20AM,and the result:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cronJobRetryTime' defined in class path resource [applicationContext-job.xml]: Cannot resolve reference to bean 'cronJobRetryImplTask' while setting bean property 'jobDetail'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cronJobRetryImplTask' defined in class path resource [applicationContext-job.xml]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodException: tv.huan.cms.services.rest.DuMiSynchronizationRetryRest.execute()
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:329)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1360)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1118)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:607)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:925)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:472)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:388)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:293)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5157)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5680)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1702)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1692)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cronJobRetryImplTask' defined in class path resource [applicationContext-job.xml]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodException: tv.huan.cms.services.rest.DuMiSynchronizationRetryRest.execute()
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:323)
... 24 more
Caused by: java.lang.NoSuchMethodException: tv.huan.cms.services.rest.DuMiSynchronizationRetryRest.execute()
at java.lang.Class.getMethod(Unknown Source)
at org.springframework.util.MethodInvoker.prepare(MethodInvoker.java:178)
at org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean.afterPropertiesSet(MethodInvokingJobDetailFactoryBean.java:198)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)
... 31 more
-----------------------first edit---------------------------
Yes,yes,samabcde's replay is effective and thanks samabcde for your patience and effort,but problems seem to be in the code itself.I try to run these codes but the job can not be executed again when the simulated exception occurred:
INFO 2018-11-02 14:43:00,022 [DuMiSynchronizationRetryRest.java,16] - enter
execute ...
INFO 2018-11-02 14:43:00,027 [DuMiSynchronizationRetryRest.java,28] -
business begin...
INFO 2018-11-02 14:43:00,027 [DuMiSynchronizationRetryRest.java,36] -
Thread begin to sleep for 3 seconds...
INFO 2018-11-02 14:43:03,028 [DuMiSynchronizationRetryRest.java,42] - job
refired ...
INFO 2018-11-02 14:43:03,031 [JobRunShell.java,221] - Job
DEFAULT.cronJobRetryImplTask threw a JobExecutionException:
org.quartz.JobExecutionException: java.lang.ArithmeticException: / by zero
[See nested exception: java.lang.ArithmeticException: / by zero]
at tv.huan.cms.services.rest.DuMiSynchronizationRetryRest.execute(DuMiSynchronizati onRetryRest.java:34)
at org.quartz.core.JobRunShell.run(JobRunShell.java:216)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)
Caused by: java.lang.ArithmeticException: / by zero
at tv.huan.cms.services.rest.DuMiSynchronizationRetryRest.execute(DuMiSynchronizat
ionRetryRest.java:30)
... 2 more
the log showed up an exception and no more clue.How can I achieve my goals?
From the Spring xml
<bean id="cronJobRetryImplTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" lazy-init="true">
<property name="targetObject">
<ref bean="cronJobRetryImpl" />
</property>
<property name="targetMethod">
<value>execute</value>
</property>
<property name="concurrent" value="false" />
</bean>
The arguments of MethodInvoker(MethodInvokingJobDetailFactoryBean
extend) is not specified, hence it assumes there is no argument. As a result the exception
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cronJobRetryImplTask' defined in class path resource [applicationContext-job.xml]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodException: tv.huan.cms.services.rest.DuMiSynchronizationRetryRest.execute()
is thrown as there is no method execute
without arguments in DuMiSynchronizationRetryRest
class.
To resolve the problem, JobDetailFactoryBean
should be used instead of MethodInvokingJobDetailFactoryBean
as said in the Java Doc of MethodInvokingJobDetailFactoryBean
Avoids the need for implementing a one-line Quartz Job that just invokes an existing service method on a Spring-managed target bean.
However, DuMiSynchronizationRetryRest
is implemented as a Quartz Job, and using execute
method of Job, which requires JobExecutionContext
. In this case, JobDetailFactoryBean
should be the appropriate factory bean. To change the factory bean, just update the bean definition of cronJobRetryImplTask as
<bean id="cronJobRetryImplTask"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean"
lazy-init="true">
<property name="jobClass">
<value>gov.housingauthority.pass.app.DuMiSynchronizationRetryRest
</value>
</property>
</bean>
Since cronJobRetryImpl
bean is not needed after the change the @Service
annotation of
can be removed also.
Finally, since StatefulJob
is deprecated, as suggested in the Java Doc of StatefulJob,
use DisallowConcurrentExecution and/or PersistJobDataAfterExecution annotations instead.
For the problem that the job does not retry immediately, this is due to using
e2.refireImmediately();
, which is a getter only.To set the refire flag:
For quartz on or before version 1.5.2,
we can use new JobExecutionException(e, true)
where the second parameter will set the refireImmediately
as true.
After version 1.7.2, setter method setRefireImmediately(boolean refireImmediately);
is provided.