Quartz长时间运行的作业完成一次,状态返回等待但无法重新安排

时间:2013-04-13 00:12:54

标签: spring quartz-scheduler

我一直遇到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();
        }
    }
}   
}

1 个答案:

答案 0 :(得分:0)

好的,问题解决了。数据库服务器上的时间和应用服务器上的时间都已消失。