本文作者:小黑黑

[Quartz.Net]Quartz.Net - 哑火策略

小黑黑 1年前 ( 2019-03-15 ) 1016 抢沙发
 [Quartz.Net]Quartz.Net - 哑火策略摘要: 一、为什么会哑火        有时我们的Quartz无法在你需要的时候运行你的工作。有以下3个原因...

一、为什么会哑火

        有时我们的Quartz无法在你需要的时候运行你的工作。有以下3个原因:

        1、所有工作线程都在忙于其他工作。

        2、调度程序本身已经关闭。

        3、开始时间安排在了过去的时间


        我们可以在初始化调度程序时来增加线程数来解决所有工作线程都在忙碌的情况。但当整个应用程序/服务器/调度程序关闭时,我们将无法做任何事情。Quartz无法触发触发器的情况成为哑火。

不同的哑火策略的配置选项取决于所选择的触发器。Quartz的行为也有所不同。具体取决于触发设置。在了解哑火策略之前,还有另外一个配置选项,它在quartz.config中的quartz.jobStore.misfireThreshold,单位为毫秒,默认为60000毫秒。它定义了触发器被认为的失效时间。如果假设触发器设置在30秒前被触发,则使用默认设置,Quartz将会把这种延迟为非哑火,并且Quartz将进行运行。但是,如果再预定时间后61秒发现触发器,那么特殊的哑火处理程序线程会处理它,遵守哑火指令。

二、简单触发而不重复

//不设置哑火策略
var trigger = TriggerBuilder.Create().StartAt(DateTime.Now.AddSeconds(-10))
                    .Build();
//显示的设置哑火策略
var trigger = TriggerBuilder.Create().StartAt(DateTime.Now.AddSeconds(-10))
                    .WithSimpleSchedule(x => x.WithMisfireHandlingInstructionFireNow())
                    .Build();

        我们将触发器安排在10秒之前运行,现实生活中,我们应该不会这样做。但是,想象一下,如果我们的触发器设置正确,但是在调度前,调度程序已经关闭或没有任何闲置的工作线程,那么Quartz将会怎样应对这种特殊情况呢?在上面的第一段代码片段中,我们没有设置哑火处理指令,在这种情况下Quartz将会使用智能策略。第二段代码片段中,我们明确定义了哑火时我们期望的行为类型。不同的哑火策略将会产生不同的行为:

指令行为
智能策略(默认)请参阅 WithMisfireHandlingInstructionFireNow
WithMisfireHandlingInstructionFireNow

在调度程序发现哑火情况后立即执行作业。

场景:我们的任务在凌晨1点执行清理系统垃圾,不幸的是,我们的应用再续由于当时故障而中断,并在凌晨2点恢复,那么我们的调度程序将会立即来执行任务。

WithMisfireHandlingInstructionIgnoreMisfires请参阅 WithMisfireHandlingInstructionFireNow
WithMisfireHandlingInstructionNextWithRemainingCount

程序将会什么都不做,失误的执行将会被忽略,没有下一次执行,如果要完全丢弃错误执行,可以使用此策略。

场景:触发器假设开始在电视中录制节目,当触发器失灵并且已经晚了2个小时,那么就没有必要开始录音。

WithMisfireHandlingInstructionNextWithExistingCount请参阅 WithMisfireHandlingInstructionNextWithRemainingCount
WithMisfireHandlingInstructionNowWithExistingCount请参阅 WithMisfireHandlingInstructionFireNow
WithMisfireHandlingInstructionNowWithRemainingCount请参阅 WithMisfireHandlingInstructionFireNow

三、简单触发重复固定次数

var trigger3 = TriggerBuilder.Create().StartAt(DateBuilder.DateOf(9, 0, 0))
                    .WithSimpleSchedule(X =>
                          X.WithRepeatCount(10)
                           .WithIntervalInHours(1)
                           .WithMisfireHandlingInstructionFireNow()
                          ).Build();

        在这个例子中,触发器假设每小时触发一次任务,共触发11次,从今天中午9点开始。假设由于某种原因调度程序无法在上午9点和10点运行作业,并且它在10:30恢复,那么我们有2次任务哑火了,调度程序在这种情况下会如何处理呢?

指令行为
智能策略(默认)请参阅 WithMisfireHandlingInstructionNowWithExistingCount
WithMisfireHandlingInstructionFireNow请参阅 WithMisfireHandlingInstructionNowWithRemainingCount
WithMisfireHandlingInstructionIgnoreMisfires

调度程序将尽快触发错误地所有触发器,然后返回普通计划。

场景:我们要每个小时生成一个报表,但在9点和10点触发器哑火,那么我们也要生成9点和10点的报表,执行完之后,它将等到11点,然后在进行触发任务。

注意:处理哑火时,同样重要的是要意思到实际的作业执行时间可能在预定时间之后,这意味着我们不能简单的依赖当前系统时间,可能会使用context.ScheduledFireTimeUtc


WithMisfireHandlingInstructionNextWithExistingCount

调度程序不会立即执行。它将会等待下一个预定时间并按计划的时间间隔运行触发器。

场景:在10:30,调度程序发现2个错误执行的任务,它会等到下一个预定时间(上午11点)并且每个小时触发一次任务,并且任务结束时间将推迟2个小时。

WithMisfireHandlingInstructionNextWithRemainingCount调度程序江丢弃哑火的任务并等待下一个计划的时间,触发器执行的总数将少于配置。
WithMisfireHandlingInstructionNowWithExistingCount

第一次哑火的触发器将立即执行。然后,调度程序等待所需的时间间隔并执行所有剩余的触发器。哑火触发器的第一个触发时间将被移动到当前时间而没有其他变化。

场景:在10:30,调度程序运行第一个哑火的执行。然后等待1个小时,并在上午11:30触发第二个,共执行11次,最后一次任务执行将推迟。

WithMisfireHandlingInstructionNowWithRemainingCount

第一次哑火的任务将立即执行,剩下的哑火任务将被丢弃。

场景:在10:30,调度程序运行第一次哑火的任务(从上午8点开始)。它将丢弃剩余的错误任务(10点的任务)并等待1个小时在执行9次触发:11:30,12:30 ....

四、简单的触发无限重复

var trigger = TriggerBuilder.Create().StartAt(DateBuilder.DateOf(9, 0, 0))
                    .WithSimpleSchedule(x =>
                         x.RepeatForever()
                          .WithIntervalInHours(1)
                          .WithMisfireHandlingInstructionFireNow()
                    ).Build();

例如,我们的任务从今天中午8点开始,每小时触发一次,但是调度程序无法在上午8点和9点运行作业,并且在中午10:30恢复,那么我们有2次触发器哑火,那么调度程序在这种情况下会如何处理呢?

指令行为
智能策略(默认)请参阅 WithMisfireHandlingInstructionNextWithRemainingCount
WithMisfireHandlingInstructionFireNow请参阅 WithMisfireHandlingInstructionNowWithRemainingCount
WithMisfireHandlingInstructionIgnoreMisfires调度程序会立即执行所有的哑火触发器,然后按计划进行。
WithMisfireHandlingInstructionNextWithExistingCount请参阅 WithMisfireHandlingInstructionNextWithRemainingCount
WithMisfireHandlingInstructionNextWithRemainingCount调度程序什么都不做,哑火的任务被丢弃,然后,调度程序在下一个计划的间隔执行。
WithMisfireHandlingInstructionNowWithExistingCount请参阅 WithMisfireHandlingInstructionNowWithRemainingCount
WithMisfireHandlingInstructionNowWithRemainingCount

第一次哑火的任务立即执行,剩余的哑火任务将会被丢弃,第一个执行任务将被调整到当前时间,并按间隔时间执行。

场景:调度程序将在10:30触发第一次(9:00)的任务,并且将10:00的任务丢弃,并等待1个小时在11:30执行下一个任务。

五、Cron触发器

        Cron触发器时Quartz中最常用的触发器,然而,还有两种可用的触发器:CalendarIntervalTrigger、DailyTimeIntervalTrigger。他们的哑火策略和Cron触发器的哑火策略是相同的。

var trigger = TriggerBuilder.Create()
                .WithCronSchedule("0 0 9-17 ? * MON-FRI", x =>
                   x.WithMisfireHandlingInstructionFireAndProceed()
                ).Build();

在此示例中,触发器在周一至周五的上午9点到下午的5点之间每小时触发一次,但是因为触发器故障,导致在9点和10点有两次没有被触发,并在10:15调度器恢复,那么调取程序在这种情况下会如何处理呢?

指令行为
智能策略(默认)请参阅 WithMisfireHandlingInstructionFireAndProceed
WithMisfireHandlingInstructionDoNothing

所有哑火的任务都将被丢弃,调度任务在下一个预定的时间执行。

场景:上午9点和10点的任务将会被丢弃,下一次将会在11:00执行。

WithMisfireHandlingInstructionFireAndProceed

立即执行第一次哑火的任务并丢弃其他哑火的任务。然后回到计划安排,无论错过多少次触发执行,都只执行一次,并且是立即执行。

场景:在上午9点和10点的任务合并并只执行一次(意味着将丢弃上午10点的任务),下一次计划执行将按时执行(11:00)

WithMisfireHandlingInstructionIgnoreMisfires

所有哑火的任务都会立即执行,然后触发器按计划运行。

场景:立即执行在上午9点和10点的任务,下一次计划执行按时执行(上午11:00)


分享到: 网站分享代码

发表评论

快捷回复:

评论列表 (暂无评论,1016人围观)参与讨论

还没有评论,来说两句吧...