ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【调度任务----Quartz】Quartz常见错误

2019-05-31 08:51:17  阅读:398  来源: 互联网

标签:quartz java 错误 调度 springframework Quartz org qrtz


1.集群之后把其中一个Quartz服务停了,其他的也不接手工作 

问题描述

集群之后,A节点执行了大多数任务,B节点大部分时间处于空闲,停掉A节点,B节点也不会接手工作。 

解决方式

修改Quartz的配置,将每个节点的org.quartz.scheduler.instanceId设置为不同的值,或者都设置为AUTO。另外org.quartz.jobStore.isClustered属性必须设为true,org.quartz.jobStore.clusterCheckinInterval属性为集群中每次检查的时间间隔(按我的理解,应该差不多等于一个服务器挂了之后,其他服务器接手的时间),单位为毫秒,默认值是15000。 

 

2.在Spring中使用Quartz的高级配置 

问题描述

Quartz集群仅能使用JDBC JobStore工作,需要在Spring中使用Quartz的高级配置

解决方式

1 通过SchedulerFactoryBean的configLocation属性指定Quartz配置文件的位置。

<bean id="quartzJobFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
    <property name="triggers">  
        <list>  
            <ref bean="clusterTesterJobScheduledTask" />  
        </list>  
    </property>  
    <property name="configLocation" value="classpath:quartz.properties" />  
</bean>  

2 通过SchedulerFactoryBean的quartzProperties属性直接配置

 

3.NotSerializableException 

问题描述

在将Quartz的Job持久化到数据库的过程中产生NotSerializableException。详细异常信息为: 

java.io.NotSerializableException: Unable to serialize JobDataMap for insertion into database because the value of property 'methodInvoker' is not serializable: org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean 

解决方式

将任务class MethodInvokingJobDetailFactoryBean 替换为 JobDetailFactoryBean

  <!-- 任务 -->
  <bean id="oaBranchDataCacheJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="group" value="ETC_REST_GROUP" />
        <property name="name" value="OaBranchDataCacheJob" />
        <!-- 没有绑定触发器仍然保留在Quartz的JobStore中 -->
        <!-- <property name="Durability" value="true"/> -->
        <property name="jobClass" value="com.c2vm.xia.rest.quartz.job.OaBranchDataCacheJob" />
    </bean>
    <!-- 调度触发器 -->
    <bean id="oaBranchDataCacheJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="group" value="ETC_REST_GROUP" />
        <property name="name" value="OaBranchDataCacheJob_trigger" />
        <property name="jobDetail" ref="oaBranchDataCacheJob" />
        <property name="cronExpression" value="0/5 * * * * ?" />
    </bean>

并修改任务Java类继承QuartzJobBean

import org.apache.log4j.Logger;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class OaBranchDataCacheJob extends QuartzJobBean {
    private Logger logger = Logger.getLogger(OaBranchDataCacheJob.class);

    public OaBranchDataCacheJob() {
        logger.info("OaBranchDataCacheJob init ..");
    }

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        System.out.println("=======【OaBranchDataCacheJob】");
    }
}

 

4.持久化时jobDetail找不到

问题描述

错误信息如下:

org.quartz.JobPersistenceException: The job (DEFAULT.studyDetail) referenced by the trigger does not exist.

解决方式

原因一般是数据源配置导致的问题。

 可能的原因是:数据源未配置成自动提交,当第一次启动trigger时,之前对数据库的job的增加的事物没有自动提交,导致后面的事物无法查询到。

如果数据源是通过dbcp配置的将自动提交配置为true

<property name="defaultAutoCommit" value="false" />

如果是c3p0配置为

autoCommitOnClose=true

 

5.错误Jobs added with no trigger must be durable

问题描述

启动时报错

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'schedulerFactoryBean' defined in ServletContext resource [/WEB-INF/conf/spring-quartz.xml]: Invocation of init method failed; nested exception is org.quartz.SchedulerException: Jobs added with no trigger must be durable.
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1512)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:610)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:410)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4738)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5181)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: org.quartz.SchedulerException: Jobs added with no trigger must be durable.
    at org.quartz.core.QuartzScheduler.addJob(QuartzScheduler.java:934)
    at org.quartz.core.QuartzScheduler.addJob(QuartzScheduler.java:927)
    at org.quartz.impl.StdScheduler.addJob(StdScheduler.java:268)
    at org.springframework.scheduling.quartz.SchedulerAccessor.addJobToScheduler(SchedulerAccessor.java:344)
    at org.springframework.scheduling.quartz.SchedulerAccessor.addTriggerToScheduler(SchedulerAccessor.java:367)
    at org.springframework.scheduling.quartz.SchedulerAccessor.registerJobsAndTriggers(SchedulerAccessor.java:305)
    at org.springframework.scheduling.quartz.SchedulerFactoryBean.afterPropertiesSet(SchedulerFactoryBean.java:508)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1571)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1509)
    ... 21 more

解决方式

在配置文件中的jobDetail bean配置里增加配置

<!-- 没有绑定触发器仍然保留在Quartz的JobStore中 -->
<property name="Durability" value="true"/>

 

 6.JobStoreCMT发生死锁

解决方式

1.当tx需要很长的时间时,某些数据库可能会误报死锁,可以加索引

// 创建单列索引
在qrtz_triggers(NEXT_FIRE_TIME)上创建索引idx_qrtz_t_next_fire_time;
在qrtz_triggers(TRIGGER_STATE)上创建索引idx_qrtz_t_state;
在qrtz_triggers(TRIGGER_STATE,NEXT_FIRE_TIME)上创建索引idx_qrtz_t_nf_st;
在qrtz_fired_triggers(TRIGGER_NAME)上创建索引idx_qrtz_ft_trig_name;
在qrtz_fired_triggers(TRIGGER_GROUP)上创建索引idx_qrtz_ft_trig_group;
在qrtz_fired_triggers(TRIGGER_NAME)上创建索引idx_qrtz_ft_trig_name;
在qrtz_fired_triggers(INSTANCE_NAME)上创建索引idx_qrtz_ft_trig_inst_name;
在qrtz_fired_triggers(JOB_NAME)上创建索引idx_qrtz_ft_job_name;
在qrtz_fired_triggers(JOB_GROUP)上创建索引idx_qrtz_ft_job_group;


// 创建联合索引
创建索引idx_qrtz_ft_trig_n_g on \
    qrtz_fired_triggers(TRIGGER_NAME,TRIGGER_GROUP);
创建索引idx_qrtz_t_next_fire_time_misfire on \
    qrtz_triggers(MISFIRE_INSTR,NEXT_FIRE_TIME);
创建索引idx_qrtz_t_nf_st_misfire on \
    qrtz_triggers(MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
创建索引idx_qrtz_t_nf_st_misfire_grp on \
    qrtz_triggers(MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);

2.检查数据源中是否有线程池连接数量+2个连接,只能多不能少

3.确保你有一个为Quartz配置的托管和非托管数据源

4.确保您使用调度程序接口完成的所有工作都是在事务中完成的。通过在SessionBean中使用调度程序来完成此操作,该调用程序的tx设置为“Required”和“Container”。或者在具有类似设置的MessageDrivenBean中。最后,自己启动一个UserTransaction,并在完成后提交工作。

5.如果任务的execute()方法使用调度程序,请通过使用UserTransaction或通过设置Quartz config属性“org.quartz.scheduler.wrapJobExecutionInUserTransaction = true”确保事务正在进行中。

 

7.quartz.properties配置filename

应该是

org.quartz.plugin.jobInitializer.fileNames = my_quartz_jobs.xml

而不是

org.quartz.plugin.jobInitializer.fileName = my_quartz_jobs.xml

这个应该和quartz的jar包版本有关,具体哪个版本使用哪个么有研究。否则会报错

Exception in thread "main" org.quartz.SchedulerException: JobStore SchedulerPlugin 'org.quartz.plugins.xml.JobInitializationPlugin' props could not be configured. [See nested exception: java.lang.NoSuchMethodException: No setter for property 'fileName']
 at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:1013)
 at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1399)
 at org.quartz.impl.StdSchedulerFactory.getDefaultScheduler(StdSchedulerFactory.java:1415)
 at com.gyb.JobScheduler.startScheduler(JobScheduler.java:28)
 at com.gyb.JobScheduler.main(JobScheduler.java:23)
Caused by: java.lang.NoSuchMethodException: No setter for property 'fileName'
 at org.quartz.impl.StdSchedulerFactory.setBeanProps(StdSchedulerFactory.java:1287)
 at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:1011)
 ... 4 more

 

8.应用服务器启动状态下,当对任务进行了修改时(即修改了job.xml中的任务明细),Quartz无法响应这种变化.也就是说,Quartz并没有进行"有状态"作业!

无论是修改了任务明细中的参数列表--JobDataMap,或是CronExpression中的定时表达式,都应该立即做出响应,并按照新的配置参数去执行这个任务.
解决方式
在quartz.properties中加入下面两行配置即可:

#自动扫描任务单并发现改动的时间间隔,单位为秒
org.quartz.plugin.jobInitializer.scanInterval = 10

#覆盖任务调度器中同名的jobDetail,避免只修改了CronExpression所造成的不能重新生效情况
org.quartz.plugin.jobInitializer.overWriteExistingJobs = true

 

9.任务被删除后,数据库不会减少任务

解决方式

可以考虑在JobDataMap中增加是否执行的配置项,即使任务会执行,但根据这种配置项,仍然可以拒绝下一步的操作.当然了,修改CronExpression使之成为一个永远不会执行到的时间也是一个办法.

或者在数据库中物理删除

标签:quartz,java,错误,调度,springframework,Quartz,org,qrtz
来源: https://blog.csdn.net/ningjiebing/article/details/89411076

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有