2

我们有一个使用 Quartz 调度作业的 Java 应用程序。我们使用的石英版本是:quartz-2.2.1

石英配置使用 JDBC 作业存储。

如果在调用石英调度程序对象的 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)

为了确保石英调度器成功启动,我们在代码中添加了重试,每 1 秒调用一次石英调度器对象的 start 方法。但是当数据库连接起来时,对quartz scheduler start 方法的调用是成功的(它不会抛出任何异常)——但是驻留在数据库中的相关触发器没有启动,也没有触发任何作业。

知道这里可能是什么问题吗?任何帮助将不胜感激。

这是石英配置,请注意我们已经启用验证查询来处理糟糕的连接(由于间歇性网络故障)

#============================================================================
# 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
4

1 回答 1

3

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

TL;DR:在构建触发器时使用适当的失火指令,或增加misfireThreshold.


如果调度程序在触发器应该触发的时候关闭,那就是失火。一旦调度器启动,Quartz 就会检查失败的作业并寻找有关如何处理它们的说明。立即运行它们?等到他们下一个预定的开火时间?要让它知道要做什么,您可以通过使用misfire instructions来明确说明,或者只是默认使用 Quartz 的智能策略,这取决于触发器类型(例如CronTrigger,具有不同的默认 misfire 策​​略SimpleTrigger)。

Trigger遗憾的是,Quartz 的食谱在解释失火指令时有点欠缺,如果您想了解更多信息,它会告诉您检查每个子类的 JavaDoc 。
因此,这个人写了一篇博客文章,其中包含所有失火说明和默认失火政策,为您提供方便。

您没有告诉我们您正在使用什么样的触发器,但您可能希望包含诸如 之类的失火指令withMisfireHandlingInstructionFireNow(),它会在调度程序启动后立即运行您的工作。


另一种选择是设置org.quartz.jobStore.misfireThreshold为高于调度程序启动所需的值。
现在,您将其设置为 1 分钟。这意味着任何比预期触发时间晚不到1 分钟触发的作业都不会被视为失火,并且会正常运行。但是,对于迟到 1 分钟以上的作业,Quartz 将为它们检查失火策略。

假设您知道调度程序始终需要不到 5 分钟的时间才能上线;然后你可以尝试设置org.quartz.jobStore.misfireThreshold = 300000,所以当作业在调度程序启动时启动时,Quartz 会看到他们迟到了不到 5 分钟,并且会让他们执行而不先检查失火策略。

于 2017-06-08T08:00:41.573 回答