我一直遇到Quartz(1.6版)的问题,在第一次完成后无法重新安排长时间运行的作业。还有其他工作可以重新安排好,但它们的运行时间通常不会超过重复时间。 (我一直指的是数据库中的作业状态)当作业开始时,它会移动到BLOCKED状态,设置prev_fire_time,将来也会设置next_fire_time 1分钟。
例如next_fire_time = 9.50,prev_fire_time = 9.49
直到9.55说,工作才结束。 (注意:该工作负责对积压的事务进行批量更新。有时需要10秒,有时需要10分钟,但积压可能会变大,所以我们希望避免将间隔设置为10分钟。
当作业完成后,状态将重新设置为WAITING,但next_fire_time仍然是过去的状态。扼杀我试图在我的本地环境中设置一个测试,每10秒重复一次,睡眠1分钟,调度程序好像处理好了。
我们使用自定义作业详细信息工厂,因此我不知道这是否会影响它。
我希望能就如何解决这个问题提出一些建议。这是产品的遗留版本,因此如果需要进行大量更改,升级库可能会很困难。
详情如下:
<bean id="baseSchedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="autoStartup" value="true"/>
<property name="dataSource" ref="baseDataSource"/>
<property name="waitForJobsToCompleteOnShutdown" value="true"/>
<property name="overwriteExistingJobs" value="true"/>
<property name="applicationContextSchedulerContextKey" value="applicationContext"/>
<property name="triggers">
<list>
<ref bean="updateRecentlyModifedchedules" />
</list>
</property>
<property name="quartzProperties">
<props>
<prop key="org.quartz.threadPool.threadCount">${org.quartz.threadPool.threadCount}</prop>
</props>
</property>
</bean>
<bean id="updateRecentlyModifedchedules"
class="org.springframework.scheduling.quartz.SimpleTriggerBean"
depends-on="springApplicationContext">
<property name="jobDetail" ref="updateRecentlyModifedchedulesJob" />
<!-- delay for 280 seconds -->
<property name="startDelay" value="280000" />
<!-- repeat every 70 seconds -->
<property name="repeatInterval" value="70000" />
</bean>
<bean id="updateRecentlyModifedchedulesJob" class="com.app.application.backoffice.quartz.MethodInvokingJobDetal">
<property name="targetBeanName" value="scheduleChangeManager" />
<property name="targetMethod" value="assetSchedules" />
<property name="concurrent" value="false" />
</bean>
自定义作业工厂:
public class MethodInvokingJobDetal implements FactoryBean, BeanNameAware, BeanClassLoaderAware,
BeanFactoryAware, InitializingBean
{
private String name;
private String group = Scheduler.DEFAULT_GROUP;
private boolean concurrent = true;
private String targetBeanName;
private String[] jobListenerNames;
private String beanName;
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private BeanFactory beanFactory;
private JobDetail jobDetail;
private String targetMethod;
public void setTargetMethod(String targetMethod)
{
this.targetMethod = targetMethod;
}
public void setName(String name)
{
this.name = name;
}
public void setGroup(String group)
{
this.group = group;
}
public void setConcurrent(boolean concurrent)
{
this.concurrent = concurrent;
}
public void setTargetBeanName(String targetBeanName)
{
this.targetBeanName = targetBeanName;
}
public void setJobListenerNames(String[] names)
{
this.jobListenerNames = names;
}
public void setBeanName(String beanName)
{
this.beanName = beanName;
}
public void setBeanClassLoader(ClassLoader classLoader)
{
this.beanClassLoader = classLoader;
}
public void setBeanFactory(BeanFactory beanFactory)
{
this.beanFactory = beanFactory;
}
protected Class<?> resolveClassName(String className) throws ClassNotFoundException
{
return ClassUtils.forName(className, this.beanClassLoader);
}
protected void prepare()
{
}
public void afterPropertiesSet() throws ClassNotFoundException, NoSuchMethodException
{
prepare();
// Use specific name if given, else fall back to bean name.
String name = (this.name != null ? this.name : this.beanName);
// Consider the concurrent flag to choose between stateful and stateless job.
Class<?> jobClass = (this.concurrent ? (Class<?>) MyMethodInvokingJob.class
: StatefulMyMethodInvokingJob.class);
// Build JobDetail instance.
this.jobDetail = new JobDetail(name, this.group, jobClass);
this.jobDetail.getJobDataMap().put("targetBeanName", targetBeanName);
this.jobDetail.getJobDataMap().put("targetMethod", targetMethod);
this.jobDetail.setVolatility(false);
this.jobDetail.setDurability(true);
// Register job listener names.
if (this.jobListenerNames != null)
{
for (int i = 0; i < this.jobListenerNames.length; i++)
{
this.jobDetail.addJobListener(this.jobListenerNames[i]);
}
}
postProcessJobDetail(this.jobDetail);
}
/**
* Callback for post-processing the JobDetail to be exposed by this FactoryBean.
* <p>The default implementation is empty. Can be overridden in subclasses.
* @param jobDetail the JobDetail prepared by this FactoryBean
*/
protected void postProcessJobDetail(JobDetail jobDetail)
{
}
/**
* Overridden to support the {@link #setTargetBeanName "targetBeanName"} feature.
*/
public Class<?> getTargetClass()
{
Class<?> targetClass = null; //super.getTargetClass();
if (targetClass == null && this.targetBeanName != null)
{
Assert.state(this.beanFactory != null, "BeanFactory must be set when using 'targetBeanName'");
targetClass = this.beanFactory.getType(this.targetBeanName);
}
return targetClass;
}
/**
* Overridden to support the {@link #setTargetBeanName "targetBeanName"} feature.
*/
public Object getTargetObject()
{
Object targetObject = null; // super.getTargetObject();
if (targetObject == null && this.targetBeanName != null)
{
Assert.state(this.beanFactory != null, "BeanFactory must be set when using 'targetBeanName'");
targetObject = this.beanFactory.getBean(this.targetBeanName);
}
return targetObject;
}
public Object getObject()
{
return this.jobDetail;
}
public Class<?> getObjectType()
{
return JobDetail.class;
}
public boolean isSingleton()
{
return true;
}
public static class StatefulMyMethodInvokingJob extends MyMethodInvokingJob
implements StatefulJob
{
// No implementation, just an addition of the tag interface StatefulJob
// in order to allow stateful method invoking jobs.
}
private static class MyMethodInvokingJob extends QuartzJobBean
{
private String targetBeanName;
private String targetMethod;
public void setTargetBeanName(String targetBeanName)
{
this.targetBeanName = targetBeanName;
}
public void setTargetMethod(String targetMethod)
{
this.targetMethod = targetMethod;
}
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException
{
Object targetObject = SpringApplicationContext.getBean(targetBeanName);
try
{
Method method = targetObject.getClass().getMethod(targetMethod);
method.invoke(targetObject);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
答案 0 :(得分:0)
好的,问题解决了。数据库服务器上的时间和应用服务器上的时间都已消失。