在数据库连接失败时重试Quartz调度程序的启动

3
我们有一个使用Quartz调度作业的Java应用程序。我们使用的Quartz版本是:quartz-2.2.1。
Quartz配置使用JDBC作业存储。
如果在调用Quartz调度程序对象的start方法时数据库连接断开(由于间歇性网络故障),则会出现以下异常:
2017-05-28 00:05:45 org.quartz.SchedulerConfigException: Failure occured during job recovery. [See nested exception: org.quartz.JobPersistenceException: Couldn't recover jobs: The connection is closed. [See nested exception: com.microsoft.sqlserver.jdbc.SQLServerException: The connection is closed.]]
2017-05-28 00:05:45     at org.quartz.impl.jdbcjobstore.JobStoreSupport.schedulerStarted(JobStoreSupport.java:692)
2017-05-28 00:05:45     at org.quartz.core.QuartzScheduler.start(QuartzScheduler.java:567)
2017-05-28 00:05:45     at org.quartz.impl.StdScheduler.start(StdScheduler.java:142)

为了确保Quartz调度程序成功启动,我们在代码中添加了重试机制,每隔1秒钟对Quartz调度程序对象的start方法进行一次调用。但是当数据库连接正常时,对Quartz调度程序start方法的调用是成功的(不会抛出任何异常),但是驻留在数据库中的相关触发器没有启动,也没有触发任何作业。
你有什么想法吗?任何帮助将不胜感激。
以下是Quartz配置,请注意,我们已经启用了验证查询以处理糟糕的连接(由于间歇性网络故障)。
#============================================================================
# Configure Main Scheduler Properties  
#============================================================================

org.quartz.scheduler.instanceName = TestScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.skipUpdateCheck=true

#============================================================================
# Configure ThreadPool  
#============================================================================

org.quartz.threadPool.class =     org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount =  50
org.quartz.threadPool.threadPriority = 5

#============================================================================
# Configure JobStore  
#============================================================================

org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.maxMisfiresToHandleAtATime = 15

org.quartz.jobStore.class =     org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass =     org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = aBPM
org.quartz.jobStore.tablePrefix = ABPM_
org.quartz.jobStore.isClustered = false
org.quartz.jobStore.useDBLocks = false
org.quartz.jobStore.acquireTriggersWithinLock = true

#============================================================================
# Configure Datasources  
#============================================================================
org.quartz.dataSource.aBPM.driver = org.hsqldb.jdbcDriver
org.quartz.dataSource.aBPM.URL = jdbc:hsqldb:file:embeddedDb/db/abpmquartz
org.quartz.dataSource.aBPM.user = sa
org.quartz.dataSource.aBPM.encryptPassword = yes
org.quartz.dataSource.aBPM.password = fMFVvEFk3gFmM9ewWQkTNg==
org.quartz.dataSource.aBPM.maxConnections = 55
org.quartz.dataSource.aBPM.validationQuery= SELECT 1

嗨,阿曼,自你发布这个问题并我回答以来已经快两个月了。如果你发现我的回答有所帮助,那么请将其标记为已接受(在投票箭头下方的复选框中)。谢谢! - walen
1个回答

3

您可能会遇到工作失火的问题。

简而言之:在构建触发器时使用适当的失火指令,或增加misfireThreshold


如果计划程序在触发器应该触发的时间停止运行,那就是一个错过。一旦计划程序启动,Quartz会检查错过的作业并查找有关如何处理它们的指令。立即运行它们?等待下一个预定的触发时间?为了让它知道该怎么做,您可以通过使用错过的指令来明确说明,或者默认使用Quartz的智能策略,这取决于触发器类型(例如,CronTrigger具有与SimpleTrigger不同的默认错过策略)。
遗憾的是,Quartz的食谱在解释错过的指令方面有点欠缺,并告诉您如果想了解更多信息,则需要检查每个Trigger子类的JavaDoc。
因此,这位家伙编写了一篇博客文章,解释了所有错过的指令和默认的错过策略,以便您参考。
你没有告诉我们你正在使用哪种触发器,但你可能想要包含失效指令,比如withMisfireHandlingInstructionFireNow(),这会在调度程序启动后立即运行你的作业。
另一种选择是将org.quartz.jobStore.misfireThreshold设置为比调度器启动时间更长的值。
现在它被设置为1分钟。这意味着任何在其预期触发时间之后不到1分钟启动的作业都不会被视为错过,并且会正常运行。但是,对于超过1分钟迟到的作业,Quartz将为它们检查错过策略。

假设您知道调度程序始终需要少于5分钟才能上线;那么您可以尝试将org.quartz.jobStore.misfireThreshold = 300000,因此当作业在调度程序启动时启动时,Quartz会看到它们晚了不到5分钟,并且会让它们执行而不首先检查misfire策略。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接