在 prod 环境中间歇性地在预定时间错过 Quartz 作业触发器

Posted

技术标签:

【中文标题】在 prod 环境中间歇性地在预定时间错过 Quartz 作业触发器【英文标题】:Quartz job trigger miss at scheduled time intermittently in prod environment 【发布时间】:2021-04-02 21:38:33 【问题描述】:

我已经通过 *** 和许多其他网站询问了许多问题,但仍然没有找到解决我的问题的运气。

我们在上午 9:30-10 之间安排了大约 35 个作业,但有时 3 到 5 个作业错过了执行,并且在运行丢失的作业后,Adhoc 运行系统从第二天开始再次正常工作。这种情况会在几天或几周后再次发生。

我们正在使用石英版本 2.2.3 和弹簧批处理版本 4.2.0.RELEASE。

我们没有覆盖调度程序线程数,因为它在很长一段时间内都可以正常工作,并且突然开始间歇性地导致某些作业失败。

以下是石英的特性,

<property name="quartzProperties">
    <props>
        <prop key="org.quartz.scheduler.skipUpdateCheck">true</prop>
        <prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop>
        <prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.StdJDBCDelegate</prop>
        <prop key="org.quartz.scheduler.instanceId">AUTO</prop>
        <prop key="org.quartz.jobStore.useProperties">false</prop>
        <prop key="org.quartz.jobStore.tablePrefix">#'$db.defaultschema' != '' ? '$db.defaultschema'+'.QRTZ_' : 'QRTZ_'</prop>
        <prop key="org.quartz.jobStore.selectWithLockSQL">SELECT * FROM 0LOCKS UPDLOCK WHERE LOCK_NAME = ?</prop>
        <prop key="org.quartz.jobStore.isClustered">true</prop>
        <prop key="org.quartz.jobStore.dataSource">dataSource</prop>
        <prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
        </prop>
    </props>
</property>

Spring 批处理作业配置:

<batch:job id="reportJob">
    <batch:step id="step1">
        <batch:tasklet>
            <batch:chunk reader="reports-reader" processor="reports-processor"
                writer="reports-writer" commit-interval="0">
            </batch:chunk>
        </batch:tasklet>
    </batch:step>
    <batch:listeners>
        <batch:listener ref="batchJobListener" />
    </batch:listeners>
</batch:job>
<bean id="reports-reader" scope="step"
    class="com.company.reportloader.reader.ReportsItemReader">
    <property name="reportsItemReaderService" ref="reportsItemReaderService"></property>
</bean>

<bean id="reports-processor" class="com.company.reportloader.processor.ReportsItemProcessor"></bean>
<bean id="reports-writer" class="com.company.reportloader.writer.ReportsItemWriter">
</bean>

覆盖 QuartzJobBean 的 executeInternal 并创建 jobParameters 以调用 spring 批处理作业,如下所示,

@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException 
  launcher.run(job, jobParameters);

任何帮助或指针都会有很大帮助。

【问题讨论】:

请告诉我如何配置或触发 spring 批处理作业。上面的配置没有说这个。 它并不总是失败,而是间歇性地在石英中丢失了一些触发器来调用作业 我找到了github.com/quartznet/quartznet/issues/735,有人可以帮助我了解根本原因。是石英问题吗? 我们正在集群环境中运行石英调度程序。具有 3-4 个调度程序节点。即使同时运行 3000 个作业并减少服务器内存,它也不会在任何其他环境(UAT、本地、QA 等)中复制。任何帮助将不胜感激解决问题。 我也查看了***.com/questions/618265/…,但仍然没有找到它的根本原因。任何建议。 【参考方案1】:

我们遇到了代码问题,我们在作业编辑功能中将失火指令更新为 2。我们通过将 qrtz_triggers 表中的 misfire_instr 设置为 0 解决了这个问题。不知何故,调度程序认为很少有作业被误触发,因此作业没有在预定时间触发。下面对于 cron-trigger 是 misfire 指令的定义,

**smart policy - default**  See: withMisfireHandlingInstructionFireAndProceed

**withMisfireHandlingInstructionIgnoreMisfires**
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICYQTZ-283    All misfired executions are 
immediately executed, then the trigger runs back on schedule.
Example scenario: the executions scheduled at 9 and 10 AM are executed immediately. 
The next scheduled execution (at 11 AM) runs on time.

**withMisfireHandlingInstructionFireAndProceed**
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW   Immediately executes first misfired execution and 
discards other (i.e. all misfired executions are merged together). Then back to 
schedule. No matter how many trigger executions were missed, only single immediate 
execution is performed.
Example scenario: the executions scheduled at 9 and 10 AM are merged and executed only 
once (in other words: the execution scheduled at 10 AM is discarded). The next 
scheduled execution (at 11 AM) runs on time.

**withMisfireHandlingInstructionDoNothing**
MISFIRE_INSTRUCTION_DO_NOTHING    All misfired executions are discarded, the scheduler 
simply waits for next scheduled time.
Example scenario: the executions scheduled at 9 and 10 AM are discarded, so basically 
nothing happens. The next scheduled execution (at 11 AM) runs on time.

在将 misfire_instr 更新为 0 后,由于智能策略(默认),一旦负载减少,quartz 会在 3-5 分钟内启动错误触发的作业。

【讨论】:

以上是关于在 prod 环境中间歇性地在预定时间错过 Quartz 作业触发器的主要内容,如果未能解决你的问题,请参考以下文章

调试桌面堆耗尽

如何在 GitHub 主仓库中获取新文件

如何在 Prod/Dev 环境中处理 CORS URL?

Oracle异常

在 iOS 中,如何根据环境(dev、hom、prod)更改启动屏幕图像?

Postgres INSERT 为 json 返回“无效的输入语法”