Quartz 关于触发器的更多内容
与作业类似,触发器相对容易操作,但也包含了一系列可定制的选项,您需要在充分利用 Quartz.NET 之前了解这些选项。此外,如前所述,有不同类型的触发器,您可以根据不同的调度需求进行选择。
触发器的通用属性
除了所有触发器类型都具有用于跟踪其标识的 TriggerKey
属性外,还有一些其他属性是所有触发器类型共有的。这些通用属性在使用 TriggerBuilder 构建触发器定义时进行设置(后续将提供示例)。
以下是所有触发器类型共有的属性列表:
JobKey
属性表示触发器触发时应执行的作业的标识。StartTimeUtc
属性表示触发器的调度何时开始生效。该值是一个 DateTimeOffset 对象,定义了特定日历日期上的某个时刻。对于某些触发器类型,触发器实际上会在开始时间触发,而对于其他触发器,它仅标记应开始遵循调度的时间。这意味着您可以存储一个触发器,其调度为“每月的第 5 天”,并在 1 月份设置 StartTimeUtc 属性为 4 月 1 日,那么首次触发会是在几个月之后。EndTimeUtc
属性表示触发器的调度何时不应再有效。换句话说,一个具有“每月第 5 天”调度的触发器,如果结束时间为 7 月 1 日,那么它最后一次触发将在 6 月 5 日。
其他需要更多解释的属性将在以下子节中讨论。
优先级
有时,当您有许多触发器(或 Quartz.NET 线程池中的工作线程较少)时,Quartz.NET 可能没有足够的资源立即触发所有预定同时触发的所有触发器。在这种情况下,您可能需要控制哪些触发器首先获得 Quartz.NET 工作线程的使用权。为此,您可以在触发器上设置优先级属性。如果有 N 个触发器同时触发,但当前只有 Z 个工作线程可用,那么优先级最高的前 Z 个触发器将首先执行。如果您没有在触发器上设置优先级,它将使用默认优先级 5。优先级可以是任何整数值,正数或负数。较大的数字表示较高的优先级。即,优先级为 7 的触发器将比优先级为 5 的触发器具有更高的优先级。
优先级仅在触发器具有相同触发时间时进行比较。计划在 10:59 触发的触发器将始终先于计划在 11:00 触发的触发器执行。
当检测到触发器的作业需要恢复时,其恢复将使用与原始触发器相同的优先级进行安排。
误触发指令
触发器的另一个重要属性是其“误触发指令”。如果持久化触发器因为调度器关闭或 Quartz.NET 线程池中没有可用线程执行作业而“错过”了其触发时间,就发生了误触发。不同的触发器类型有不同的误触发指令可供选择。默认情况下,它们使用“智能策略”指令——其行为基于触发器类型和配置动态变化。当调度器启动时,它会搜索任何已误触发的持久化触发器,并根据它们各自的配置误触发指令更新每一个触发器。当您开始在自己的项目中使用 Quartz.NET 时,您应该熟悉给定触发器类型上定义的误触发指令,并在其 API 文档中进行解释。关于误触发指令的更具体信息将在特定于每种触发器类型的教程课程中给出。
日历
实现 ICalendar
接口的 Quartz.NET 日历对象可以在触发器存储在调度器中时与触发器关联。日历对于从触发器的触发计划中排除时间段很有用。例如,您可以创建一个每天上午 9:30 触发作业的触发器,然后添加一个日历,排除业务的所有节假日。
日历可以是实现 ICalendar
接口的任何可序列化对象,接口如下所示:
namespace Quartz
{
public interface ICalendar
{
string Description { get; set; }
ICalendar CalendarBase { set; get; }
bool IsTimeIncluded(DateTimeOffset timeUtc);
DateTime GetNextIncludedTimeUtc(DateTimeOffset timeUtc);
ICalendar Clone();
}
}
尽管日历可以 “排除” 时间段,窄至毫秒级别,但您可能更感兴趣的是 “排除” 整个日期。为了方便起见,Quartz.NET 包括了 HolidayCalendar 类,它正是为此目的设计的。
日历必须通过 AddCalendar(..)
方法实例化并注册到调度器中。如果您使用 HolidayCalendar
,在实例化后,您应该使用其 AddExcludedDate(DateTime date)
方法来填充您希望从调度中排除的日期。同一个日历实例可以与多个触发器一起使用,如下所示:
日历示例
HolidayCalendar cal = new HolidayCalendar();
cal.AddExcludedDate(someDate);
await sched.AddCalendar("myHolidays", cal, false);
ITrigger t = TriggerBuilder.Create()
.WithIdentity("myTrigger")
.ForJob("myJob")
.WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(9, 30)) // execute job daily at 9:30
.ModifiedByCalendar("myHolidays") // but not on holidays
.Build();
// .. schedule job with trigger
ITrigger t2 = TriggerBuilder.Create()
.WithIdentity("myTrigger2")
.ForJob("myJob2")
.WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(11, 30)) // execute job daily at 11:30
.ModifiedByCalendar("myHolidays") // but not on holidays
.Build();
// .. schedule job with trigger2
上述代码创建了两个触发器,每个都安排每日触发。然而,任何原本在日历排除时段内发生的触发都将被跳过。
请参阅 Quartz.Impl.Calendar 命名空间,其中包含了许多可能满足您需求的 ICalendar
实现。