ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Quartz.NET 杂项特性指南:ISchedulerPlugin 插件体系、JobFactory 扩展与 Quartz.Jobs 预置作业

Quartz.NET 杂项特性指南:ISchedulerPlugin 插件体系、JobFactory 扩展与 Quartz.Jobs 预置作业 任务调度后端【免费下载链接】quartznetQuartz Enterprise Scheduler .NET项目地址https://gitcode.com/gh_mirrors/qu/quartznet点击查看免费下载本文以 Quartz.NET 官方文档 quartz-3.x 杂项特性Miscellaneous Features 为骨架结合当前仓库源码进行纵深解读。文章聚焦三个主题通过ISchedulerPlugin向调度器插入额外功能插件体系、通过IJobFactory接管作业实例的创建依赖注入入口、以及Quartz.Jobs包中开箱即用的工具型作业发邮件、扫描目录等。读完本文你将掌握 Quartz.NET 扩展点的注册方式、生命周期细节与配置写法并能在自己的调度应用中直接复用这些能力。一、Plug-Ins为调度器插入额外功能1.1 ISchedulerPlugin 是什么ISchedulerPlugin是 Quartz.NET 提供的一组扩展点接口允许第三方代码插入调度器从而扩展其行为。任何插件都可以做几乎任何事但最有价值的插件通常以两种方式与调度器交互主动方式直接调用调度器上的动作如调度/取消作业、暂停/恢复触发器被动方式作为IJobListener、ITriggerListener、ISchedulerListener的载体在作业触发、触发器完成、调度器生命周期事件发生时被动响应。该接口定义在 src/Quartz/Extensibility/ISchedulerPlugin.cs其注释明确写道插件通过AddPlugin或quartz.plugin.name.*配置键注册到调度器由调度器负责初始化并启动它。1.2 插件的生命周期契约ISchedulerPlugin定义了三个生命周期方法后两个带有默认实现即可选方法调用时机说明ValueTask Initialize(string pluginName, IScheduler scheduler, CancellationToken)调度器创建期间给插件一次初始化机会。注意此刻调度器的IJobStore尚未装配完成因此不适合在此访问 JobStore。若需要外部直接引用插件可在Initialize中把自身实例放入调度器的SchedulerContextValueTask Start(CancellationToken)调度器启动时通知插件现在可以安全地向调度器发起调用了。多数插件把工作都放在Initialize里挂监听器、注册解析器等无需实现此方法ValueTask Shutdown(CancellationToken)调度器关闭时通知插件释放资源。同样默认什么都不做三个方法都是ValueTask形态支持异步初始化与清理——这保证了插件可以在初始化/关闭阶段执行 I/O 或等待其他异步操作。1.3 插件的注册方式从 src/Quartz/Configuration/IQuartzBuilder.cs 的源码注释与重载可以归纳出三种注册形态容器构建AddPluginT(string? name null)由依赖注入容器构建插件实例调用方构建AddPluginT(FuncIServiceProvider, T factory, string? name null)由调用方手工创建并配置插件选项配置AddPluginT, TOptions(ActionTOptions? configure, string? name null)通过强类型TOptions配置插件。关于name参数源码注释给出重要提示name 是调度器对插件的标识某些插件会从它派生持久化作业与触发器的键因此它属于部署身份的一部分而不仅仅是个标签同一个 name 也对应quartz.plugin.name.*配置键。未指定时默认使用插件类型名。Quartz 自带的插件统一使用惯例短名xml、json、jobHistory等。除了代码注册插件也可以通过quartz.plugin.name.*风格的字符串配置键装配。在 src/Quartz/Configuration/SchedulerPluginFactory.cs 中可以看到quartz.plugin.name.type条目决定插件类型quartz.plugin.name.property键会按属性名应用到插件实例上由 src/Quartz/Configuration/PropertyBinder.cs 执行绑定。典型配置文件写法如下# 以 XML 调度数据插件为例 quartz.plugin.xml.type Quartz.Plugins.Xml.XmlSchedulingDataProcessorPlugin, Quartz.Plugins quartz.plugin.xml.fileNames ~/quartz_jobs.xml quartz.plugin.xml.failOnFileNotFound true quartz.plugin.xml.failOnSchedulingError false # 0 表示只读一次大于 0 表示以秒为单位定期扫描文件 quartz.plugin.xml.scanInterval 10说明scanInterval对应的源码属性带有[TimeSpanParseRule(TimeSpanParseRule.Seconds)]标注见 src/Quartz.Plugins/Plugins/Xml/XmlSchedulingDataProcessorPlugin.cs即配置中以秒为单位书写。当前仓库代码里推荐优先使用强类型扩展方法见下文字符串键仍然兼容。1.4 Quartz.Plugins 自带插件随 Quartz 发布的插件位于Quartz.Plugins命名空间程序集Quartz.Plugins源码目录 src/Quartz.Plugins/Plugins主要分两类1调度数据加载类——在调度器启动时自动把作业与触发器装入调度器插件类作用XmlSchedulingDataProcessorPlugin读取 XML 文件格式受job_scheduling_data_2_0.xsd约束支持simple、cron、calendar-interval三类触发器在初始化阶段把其中声明的作业与触发器加入调度器JsonSchedulingDataProcessorPlugin读取 JSON 格式的调度配置文件。源码注释指出XML 格式已冻结在 2.0 版 XSD 上无法表达后来新增的触发器种类与设置需要更丰富表达能力的调度请改用 JSON 格式后者是当前维护的格式2执行历史日志类——记录作业与触发器的事件历史插件类作用LoggingJobHistoryPlugin以经典编号占位符格式记录作业执行历史即将触发、执行成功、执行失败、被否决StructuredLoggingJobHistoryPlugin同上但使用结构化消息模板{JobGroup}、{FireTime}便于结构化日志管道索引LoggingTriggerHistoryPlugin以经典编号占位符格式记录触发器事件触发、错过、完成StructuredLoggingTriggerHistoryPlugin触发器事件的结构化模板版本以LoggingJobHistoryPlugin为例源码 src/Quartz.Plugins/Plugins/History/LoggingJobHistoryPlugin.cs其默认即将触发消息模板为Job {1}.{0} fired (by trigger {4}.{3}) at: {2:HH:mm:ss MM/dd/yyyy}其中占位符依次为0作业名、1作业组、2当前时间、3触发器名、4触发器组、5计划触发时间、6下次计划触发时间、7重新执行计数refire count。这些模板均可通过配置覆盖。1.5 推荐的代码配置方式强类型扩展方法Quartz.Plugins程序集提供了强类型扩展方法见 src/Quartz.Plugins/PluginConfigurationExtensions.cs每个插件都注册为普通服务、由容器构造可获得构造器注入再以强类型选项配置UseXmlSchedulingConfiguration(params string[] files)/UseXmlSchedulingConfiguration(ActionFileSchedulingOptions)UseJsonSchedulingConfiguration(...)同上的 JSON 版本UseJobHistoryLogging(...)/UseTriggerHistoryLogging(...)经典编号模板UseStructuredJobLogging(...)/UseStructuredTriggerLogging(...)结构化模板官方推荐作为更好的默认选择FileSchedulingOptions提供以下配置项选项默认值说明FilesListstring空要加载的调度文件列表~/前缀表示内容根目录FailOnFileNotFoundtrue文件缺失时是否让初始化失败抛异常FailOnSchedulingErrorfalse加载过程中的调度错误是否致命ScanIntervalTimeSpan.Zero多久重新扫描一次文件以感知变更0表示只读一次仓库中的示例 ConfigureJobSchedulingByUsingXmlConfigurationsExample.cs 给出了完整的组合用法调度器不通过代码注册任何作业与触发器而是交给 XML 插件从quartz_jobs.xml读取并设置ScanInterval TimeSpan.FromSeconds(10)使其运行时持续监视文件——编辑文件即可调整调度无需停止应用。对应的 XML 文件示例见 quartz_jobs.xml展示了job-scheduling-data、processing-directives、schedule以及simple触发器的完整写法。限制从XmlSchedulingDataProcessorPlugin的源码注释可以确认定期扫描文件变更目前不支持在集群环境下使用多节点部署时如需热更新调度应改用其他方案如通过调度 API 动态调整而非文件扫描。二、JobFactory接管作业实例的创建2.1 默认行为SimpleJobFactory当一个触发器触发时调度器需要通过JobFactory实例化与之关联的IJob。Quartz.NET 的默认实现是SimpleJobFactory源码 src/Quartz/Impl/SimpleJobFactory.cs它做的事情非常直接通过作业类的公共无参构造函数激活一个新实例。源码注释将其描述为 The default JobFactory used by Quartz - simply activates the job class through its public parameterless constructor。因此想让默认工厂工作作业类必须有一个可访问的无参构造函数如果作业需要构造函数注入或其他初始化就需要自定义IJobFactory。2.2 IJobFactory 接口契约IJobFactory定义在 src/Quartz/Extensibility/IJobFactory.cs包含两个方法ValueTaskJobScope CreateJob(TriggerFiredBundle bundle, IScheduler scheduler, CancellationToken cancellationToken default); ValueTask ReturnJob(JobScope scope, CancellationToken cancellationToken default);CreateJob在触发器触发时被调度器调用负责产出IJob实例连同每次触发的状态一起包装进JobScope返回。TriggerFiredBundle中携带IJobDetail及本次触发相关的全部信息。ReturnJob作业执行结束后由调度器调用用于销毁/清理作业实例。调度器会为CreateJob返回的每个 scope 调用它无论作业成功、失败还是被否决但CreateJob自身抛异常时不会调用——因此若工厂在失败前已分配了资源需要自行负责清理Quartz 自带工厂的做法是在重新抛出前自己调用ReturnJob。接口注释还强调了两个工程细节异常语义CreateJob抛出异常应极其罕见仅在完全无法实例化并准备作业时。一旦抛出调度器会把与该作业关联的所有触发器移入TriggerState.Error状态需要人工干预例如修复配置问题后重启应用。异步注意事项CreateJob若写成async其同步部分返回时会恢复调用方的ExecutionContext工厂在构建作业期间设置的AsyncLocalT将无法抵达IJob.Execute对应 issue #1528。因此建议同步的方法体保持同步无需等待时返回已完成的ValueTask。2.3 自定义 JobFactory把 IoC/DI 容器接入 Quartz自定义 JobFactory 的核心动机是让应用自己的 IoC 或 DI 容器来创建并初始化作业实例——这样作业类可以声明构造函数依赖由容器负责解析。实现方式新建一个实现IJobFactory的类在CreateJob中从容器解析bundle.JobDetail.JobType对应的类型并返回实例然后在构建调度器时通过IQuartzBuilder.UseJobFactory注册UseJobFactoryT()注册一个工厂类型由容器构建见 src/Quartz/Configuration/IQuartzBuilder.csUseJobFactory(IJobFactory jobFactory)直接传入工厂实例同文件 L189。官方提供的另一工厂实现是PropertySettingJobFactorysrc/Quartz/Impl/PropertySettingJobFactory.cs它会额外把作业JobDataMap中的属性设置到新实例的属性上。2.4 更简单的选择内置 Microsoft DI 集成如果你的主要诉求是让作业从容器获得依赖不必从零写 JobFactory——从 Quartz 3.1 起Quartz.NET 内置了 Microsoft Dependency Injection 集成详见 Microsoft DI 集成指南它同样支持接入其他 IoC 容器。借助Quartz.Extensions.DependencyInjection包作业可以直接声明构造函数依赖并自动获得解析。三、Factory-Shipped JobsQuartz.Jobs 开箱即用的工具作业3.1 安装与概览Quartz.JobsNuGet 包提供了一批拿来即用的工具型作业位于Quartz.Jobs命名空间源码目录 src/Quartz.Jobs/Jobs。安装方式dotnet add package Quartz.Jobs根据 src/Quartz.Jobs/README.md 的作业总表作业功能DirectoryScanJob监视目录当文件被新增、修改或删除时回调IDirectoryScanListenerFileScanJob监视单个文件文件变化时回调IFileScanListenerNativeJob在独立进程中运行本地可执行程序SendMailJob以配置的内容向配置的收件人发送电子邮件另外仓库中还包含NoOpJob等辅助作业。命名空间说明这些作业在 Quartz 3 时代使用单数命名空间Quartz.Job当前仓库4.x为Quartz.Jobs。由配置字符串或持久化JOB_CLASS_NAME引用旧拼写的场景仍可解析但会输出警告。3.2 配置模型JobDataMap 键 强类型 Options这些作业统一从JobDataMap读取配置键是持久化形式同时每个作业都配有对应的强类型 Options 类型与扩展方法UsingSendMailOptions、UsingDirectoryScanOptions、UsingFileScanOptions、UsingNativeJobOptions既防止键拼写错误也防止值类型错误。这些扩展方法既可用于JobBuilder.CreateTJob()也可用于AddJobTJob(…)返回的 configurator。以发送邮件为例README 示例builder.Services.AddQuartz(q q.ScheduleJobSendMailJob( trigger trigger.WithIdentity(nightlyDigest).WithCronSchedule(0 0 6 * * ?), job job.UsingSendMailOptions(new SendMailOptions { SmtpHost smtp.example.com, Sender schedulerexample.com, Recipient opsexample.com, Subject Nightly digest, Message Everything ran., })));3.3 SendMailJob 细节SendMailJob源码 src/Quartz.Jobs/Jobs/SendMailJob.cs通过作业数据键配置邮件内容。其键包括JobDataMap 键必填性说明smtp_host必填SMTP 服务器主机名smtp_port可选SMTP 服务器端口smtp_username/smtp_password可选旧版认证凭据。注意当前实现更推荐向容器注册ICredentialsByHost实例来提供 SMTP 凭据因为作业数据是持久化、集群复制且可在 Dashboard 中可见的不适合存放密码旧键仅在未注册凭据时被读取带警告3.4 DirectoryScanJob 细节DirectoryScanJob源码 src/Quartz.Jobs/Jobs/DirectoryScanJob.cs监视目录内容变化其作业数据键如下JobDataMap 键默认值说明DIRECTORY_NAME—被监视目录建议绝对路径DIRECTORY_NAMES—多个目录以分号;分隔DIRECTORY_PROVIDER_NAME—指定IDirectoryProvider类型名由其提供要监视的目录列表DIRECTORY_SCAN_LISTENER_NAME—指定IDirectoryScanListener两种提供方式推荐在 DI 容器注册监听器实现并按类型名引用旧方式是把监听器实例存入SchedulerContextMINIMUM_UPDATE_AGE5000毫秒文件最后修改时间至少过去多少毫秒才视为新/已变更避免扫描时其他进程还在写文件该作业带有[DisallowConcurrentExecution]与[PersistJobDataAfterExecution]特性因此同一时间只运行一个实例且执行后持久化内部状态如LAST_MODIFIED_TIME记录用于跨次执行比较文件修改时间。3.5 使用场景建议发邮件SendMailJob适合调度器触发后通知/告警场景如每日摘要、失败告警目录监视DirectoryScanJob/FileScanJob适合文件到达即处理的数据管道场景把扫描与处理解耦——扫描作业只负责在内容变化时回调监听器具体处理逻辑由你实现的IDirectoryScanListener/IFileScanListener承担外部程序NativeJob用于需要拉起独立进程执行本地可执行文件的场景。如需更完整的配置与示例可进一步阅读包级文档 quartz-jobs 与 quartz-plugins以及仓库中对应的集成示例Quartz.Examples/12_ConfigureJobSchedulingByUsingXmlConfigurations。小结Quartz.NET 的三个杂项扩展点分别解决了不同层级的定制需求ISchedulerPlugin面向调度器生命周期级的横切能力——自动加载调度数据、记录执行历史、在启动/关闭时挂钩子注册方式涵盖代码AddPlugin与配置键quartz.plugin.name.*两种并有强类型扩展方法可组合使用IJobFactory面向作业实例化这一精准时机——默认的无参构造工厂之外你可以把任何 IoC/DI 容器接入CreateJob而 3.1 起的 Microsoft DI 集成让常规场景无需手写工厂Quartz.Jobs包则直接提供高频场景的成品作业发邮件、扫描目录/文件、运行本地程序配合强类型 Options 扩展方法即可低门槛接入调度。三者叠加构成了调度器可扩展、作业可注入、任务可复用的完整生态是你在架构设计阶段值得优先考虑的扩展方向。赞分享任务调度后端【免费下载链接】quartznetQuartz Enterprise Scheduler .NET项目地址https://gitcode.com/gh_mirrors/qu/quartznet点击查看免费下载相关推荐Quartz.NET 杂项特性全解析Scheduler 插件、JobFactory 与内置工具 Job 实战指南Quartz.NET 杂项特性全解析Scheduler 插件、JobFactory 与内置工具 Job 实战指南 本文基于 Quartz.NET 仓库中的 L任务调度后端Quartz.NET 进阶特性全解Scheduler 插件、JobFactory 与内置工具 JobMiscellaneous Features 深度指南Quartz.NET 进阶特性全解Scheduler 插件、JobFactory 与内置工具 JobMiscellaneous Features 深度指南任务调度后端Quartz.NET终极扩展指南掌握自定义JobFactory与JobStore实现技巧Quartz.NET终极扩展指南掌握自定义JobFactory与JobStore实现技巧 Quartz.NET作为功能强大的企业级任务调度框架提供了灵活的扩任务调度后端上一篇ParsecVDisplay游戏串流和远程工作的终极虚拟显示器解决方案下一篇终极指南如何用League Director打造专业级《英雄联盟》回放视频创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表