我正在使用SimpleTrigger来安排一个应该无限期运行的作业(重复计数-1)。
我正在使用JDBC存储来保存DB中的作业状态。
但触发器在某些时间间隔内触发(在我的情况下始终为8)并进入BLOCKED状态。具体而言,TRIGGERS_STATE的值将在QRTZ_TRIGGERS表中更改为BLOCKED。注意我的Quartx表前缀是QRTZ_ 以下是我的工作触发信息。
重复计数:-1, 重复间隔:6秒, 开始延迟:10秒
MY石英配置:
#===============================================================
#Configure ThreadPool
#===============================================================
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
#===============================================================
#Configure JobStore
#===============================================================
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.maxMisfiresToHandleAtATime=20
# Flag to turn off to ignore all misfires
scheduler.ignoreMisfire=no
# Configuring JDBCJobStore with the Table Prefix
org.quartz.jobStore.tablePrefix = QRTZ_
# Using DriverDelegate
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.useProperties = false
计划程序类:
public static void scheduleJob(Class<? extends Job> job,JobDataMap dataMap)
{
Scheduler scheduler = schedulerFactoryBean.getScheduler();
try
{
JobDetail jobDetail = newJob(job)
.withIdentity(job.getSimpleName()+"_"+DateUtil.getSystemDate(), job.getSimpleName() + "_group")
.storeDurably()
.usingJobData(dataMap)
.requestRecovery()
.build();
SimpleTrigger trigger = (SimpleTrigger) newTrigger()
.withIdentity(job.getSimpleName() + "_trigger_"+DateUtil.getSystemDateWithMs(), job.getSimpleName() + "_trigger_group")
.startNow()
.withSchedule(simpleSchedule().repeatSecondlyForever(10).withMisfireHandlingInstructionFireNow())
.build();
scheduler.scheduleJob(jobDetail, trigger);
//logger.debug(scheduler.getMetaData().toString());
scheduler.start();
}
catch (SchedulerException e)
{
e.printStackTrace();
throw new SchedulerException("", e);
}
}
工作班:
@PersistJobDataAfterExecution
public class MyJob Implements Job
{
private SessionFactory sessionFactory;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException
{
getBeansFromContext(context);
Session session = sessionFactory.openSession(); // Hibernate Session Factory
// to do some DB opetations
}
private void getBeansFromContext(JobExecutionContext context) throws SchedulerException
{
ApplicationContext applicationContext = (ApplicationContext)context.getScheduler().getContext().get("applicationContext");
this.sessionFactory=applicationContext.getBean(SessionFactory.class);
}
}
Quartz调度程序工厂的Spring bean配置。
<beans:bean id="schedulerFactoryBean"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<beans:property name="jobFactory">
<beans:bean class="org.springframework.scheduling.quartz.SpringBeanJobFactory"></beans:bean>
</beans:property>
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="transactionManager" ref="txManager" />
<beans:property name="configLocation"
value="resources/scheduler/Scheduler.properties" />
<beans:property name="applicationContextSchedulerContextKey"
value="applicationContext" />
<beans:property name="autoStartup" value="true" />
</beans:bean>
<beans:bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"
p:corePoolSize="5" p:maxPoolSize="10" p:queueCapacity="100"
p:waitForTasksToCompleteOnShutdown="true" />
非常感谢任何帮助。提前致谢
答案 0 :(得分:2)
我终于理解了这个问题并且能够解决它。
正如@zerologiko评论的那样,问题在于交易。 我正在使用Spring管理的事务与hibernate。一旦我声明了我的交易政策,Spring负责交易的开始/结束。
我案中的问题原因: Spring Bean生命周期在Scheduler Job中无效。详细说明一下, 在主帖中给出我甚至不得不使用
访问我的作业类中的applicationContextjobContext.getScheduler()的getContext()得到( “的applicationContext”);。。
我正在尝试在作业完成后将某个状态更新回到我们的一个事务数据库中。
我最初没想到即使交易也是由Spring控制的。 从作业类触发这些db更新时,在我的业务方法上声明的事务不起作用。
根据我的理解,触发器将被获取,因为完成工作的线程无法回到池中。
要解决此问题,我手动打开/关闭了我的作业类中的事务,而不依赖于Spring CMT,并且它没有问题。
希望这可以帮助那些面临同样问题的人。
答案 1 :(得分:0)
我遇到了与CRON触发器类似的问题,根本原因也是由于Spring托管事务。
但是,我为解决问题所做的工作与你的有点不同。
我在代码级别保留了@Transactional注释,而是为Quartz配置了一个专用的dataSource,用于自己的数据库操作,而不需要Spring的干预。
<!-- Datasource used by Quartz -->
<bean id="quartzDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.user}"/>
<property name="password" ref="dbPassword"/>
<property name="maxActive" value="${db.conn.pool.maxActive:30}"/>
<property name="maxIdle" value="${db.conn.pool.maxIdle:15}"/>
<property name="minIdle" value="${db.conn.pool.minIdle:0}"/>
</bean>
<!-- Datasource used by Quartz -->
<!-- Assign an dedicated dataSource to quartz scheduler-->
<bean id="cronJobScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="configLocation" value="classpath:META-INF/quartz/quartz.properties"/>
<property name="jobFactory" ref="springBeanJobFactory"/>
<property name="dataSource" ref="quartzDataSource"/>
</bean>