
任务调度后端【免费下载链接】quartznetQuartz Enterprise Scheduler .NET项目地址https://gitcode.com/gh_mirrors/qu/quartznet点击查看免费下载调度器监听器SchedulerListener是 Quartz.NET 中与ITriggerListener、IJobListener并列的第三类监听机制但它监听的并非某个具体 Job 或 Trigger 的个体行为而是调度器自身的生命周期与全局事件Job/Trigger 的添加与移除、暂停与恢复、调度器启停与关闭、内部严重错误等。通过本文你将掌握ISchedulerListener接口的完整回调语义、注册方式直接注册与依赖注入两种路径、内部触发链路以及一个可直接落地的 ASP.NET Core 集成示例。本指南源自 Quartz.NET 官方教程 Lesson 8并对照当前仓库中 ISchedulerListener.cs、QuartzScheduler.cs 等源码展开纵深讲解帮助你把文档知识落到实际调用链上。什么是 SchedulerListenerSchedulerListener 与 Trigger/Job 监听器的最大区别在于关注粒度IJobListener在 Job 执行前后收到JobToBeExecuted/JobWasExecuted通知围绕某一次 Job 执行ITriggerListener在 Trigger 触发前后收到TriggerFired/TriggerComplete通知围绕某一次 Trigger 触发ISchedulerListener收到的是调度器层面的结构性事件——Job 被调度、Trigger 被移除、Trigger 永远不会再触发、整组 Trigger/Job 被暂停或恢复、调度器出错、调度器关闭等不必然与某个具体的 Trigger 或 Job 相关。用官方文档scheduler-listeners.md的原话概括SchedulerListener 接收的是调度器自身内部发生的事件而非绑定在特定 Trigger 或 Job 上的事件。从源码结构看ISchedulerListener定义在 src/Quartz/ISchedulerListener.cs所有回调的第一个参数都是触发通知的IScheduler实例这意味一个监听器实例可以在同一宿主内同时服务多个调度器并通过参数区分究竟是哪个调度器暂停了 Trigger 或发生了故障。ISchedulerListener 接口全解接口演进从旧版到当前仓库版本官方教程对应 Quartz 1.x 时代展示的接口是同步风格只有 9 个回调public interface ISchedulerListener { void JobScheduled(Trigger trigger); void JobUnscheduled(string triggerName, string triggerGroup); void TriggerFinalized(Trigger trigger); void TriggersPaused(string triggerName, string triggerGroup); void TriggersResumed(string triggerName, string triggerGroup); void JobsPaused(string jobName, string jobGroup); void JobsResumed(string jobName, string jobGroup); void SchedulerError(string msg, SchedulerException cause); void SchedulerShutdown(); }而当前仓库Quartz.NET 4.x中的 ISchedulerListener.cs 已全面重构为异步ValueTask 默认实现default interface methods风格回调数量大幅扩充且每个方法都接收IScheduler scheduler与CancellationToken。这意味着实现类只需覆写自己关心的事件其余回调走默认空实现不必像旧版那样为每个方法都写空壳所有通知都是异步可取消的与调度器内部的async工作流保持一致Name属性默认返回实现类型名用于监听器的注册与移除标识。当前仓库中的完整回调清单按事件类别整理如下方法签名以 ISchedulerListener.cs 为准事件类别回调方法触发时机调度/移除JobScheduled一个 Job 被 Trigger 调度时携带该ITrigger调度/移除JobUnscheduled一个 Trigger及其绑定的调度被移除时携带TriggerKey调度/移除JobAdded/JobDeletedJob 被加入 / 删除时携带IJobDetail/JobKey调度/移除SchedulingDataCleared所有 Job、Trigger、Calendar 被清空时生命周期终结TriggerFinalizedTrigger 达到永远不再触发条件时暂停/恢复TriggerPaused/TriggersPaused单个 / 整组 Trigger 被暂停暂停/恢复TriggerResumed/TriggersResumed单个 / 整组 Trigger 被恢复暂停/恢复JobPaused/JobsPaused单个 / 整组 Job 被暂停暂停/恢复JobResumed/JobsResumed单个 / 整组 Job 被恢复错误SchedulerError调度器内部发生严重错误如 JobStore 反复失败、Job 实例化失败携带SchedulerErrorContext错误TriggerInError/TriggersInError单个 Trigger / 某 Job 的全部 Trigger 进入Error状态中断JobInterrupted两个重载Job 被中断带fireInstanceId的重载可精确到是哪一次执行被中断启停SchedulerStarting/SchedulerStarted/SchedulerInStandbyMode调度器启动中 / 已启动 / 进入待机启停SchedulerShuttingDown/SchedulerShutdown调度器开始关闭序列 / 已关闭几个值得注意的细节均有源码注释佐证SchedulerError携带SchedulerErrorContext见 SchedulerErrorContext.cs它封装了出错时调度器所知的 Trigger、Job 与 firing 上下文监听器可以直接据此暂停肇事 Trigger而无需从错误消息文本里手工解析 Key。JobInterrupted的两个重载带fireInstanceId的重载用于无DisallowConcurrentExecutionAttribute的 Job同一时刻可能有多个 firing 并发执行默认实现会转而调用仅带JobKey的旧重载保证老代码继续可用。官方注释明确建议二选一实现不要两个都覆写。TriggersPaused/JobsPaused的string?参数为 null 时表示所有组对应暂停全部的操作。TriggerInError说明发生了什么而非为什么导致原因单独通过SchedulerError例如JobInstantiationException到达也有些错误转换完全发生在 JobStore 侧无法加载 Job 类型调度器侧根本没有 cause。注册与移除三种可用方式与 Job/Trigger 监听器不同SchedulerListener没有全局与非全局之分——它天然就是调度器级别的任何实现了ISchedulerListener的对象都可以注册。当前官方文档与源码均确认这一点。方式一通过 IListenerManager 直接注册经典方式IScheduler暴露了ListenerManager属性接口定义见 IListenerManager.cs支持按名称注册、替换与移除// 注册同名已存在则替换 scheduler.ListenerManager.AddSchedulerListener(myListener); // 按监听器的 Name 移除返回是否成功移除 bool removed scheduler.ListenerManager.RemoveSchedulerListener(myListener.Name); // 查询 IReadOnlyListISchedulerListener all scheduler.ListenerManager.GetSchedulerListeners(); ISchedulerListener? byName scheduler.ListenerManager.GetSchedulerListener(name);底层实现位于 ListenerManagerImpl.cs监听器保存在一个按注册顺序排列的OrderedDictionarystring, ISchedulerListener中内部有锁保护注册与移除是线程安全的。同名注册会直接替换旧实例——这是当前仓库 ISchedulerListener.cs 中Name注释反复强调当同一类型注册多个实例时必须覆写 Name的原因同名注册会相互覆盖若不覆写 Name 则后来的实例会顶掉先前的实例。注册时还会做形状校验VerifyShape由于所有回调都有默认实现一个签名不符的同名公共方法也会编译通过、但实际不实现任何回调——这种死方法监听器会被拒绝并抛出SchedulerConfigException而不是被静默挂载后永不调用。方式二通过 QuartzBuilder 配置依赖注入 / 服务化方式在 DI 场景Quartz.Extensions.DependencyInjection中QuartzBuilder提供了三个泛型重载见 QuartzBuilder.cs// 由 DI 容器按类型创建需要 PublicConstructors 可达性 q.AddSchedulerListenerMySchedulerListener(); // 直接传入实例 q.AddSchedulerListener(new MySchedulerListener()); // 用工厂函数从 IServiceProvider 构建 q.AddSchedulerListener(sp new MySchedulerListener(sp.GetRequiredServiceILoggerMySchedulerListener()));初始化时SchedulerContentInitializer.cs 会依次把注册项与以普通 DI 服务形式注册的ISchedulerListener装配进scheduler.ListenerManager并做了去重处理——若同一实例既走 builder 注册又注册为 DI 服务不会收到两次通知。方式三SchedulerEventPlugin配置文件方式仓库还内置了基于配置文件注册的SchedulerEventPlugin见 SchedulerEventPlugin.cs可通过 quartz 属性文件为调度器装配监听器适合非 DI 的传统配置场景。内部触发链路通知从哪来、往哪去SchedulerListener 的通知并非由某个独立线程广播而是由调度器主流程在事件发生的同步/异步路径上显式调用。核心分发点集中在 QuartzScheduler.cs从源码 grep 出的调用点可以还原典型链路调度事件ScheduleJob成功后调用NotifySchedulerListenersScheduled(trigger, ...)QuartzScheduler.cs、#L937、#L1554、#L1585 等多处RescheduleJob则先NotifySchedulerListenersUnscheduled再NotifySchedulerListenersScheduled#L1295-L1296移除事件UnscheduleJob、DeleteJob、Clear路径分别触发NotifySchedulerListenersUnscheduled#L1166、#L1189、#L1210、#L1295、#L2125暂停/恢复PauseTrigger/PauseTriggers/PauseJob/PauseJobs触发对应NotifySchedulerListenersPausedTrigger(s)/PausedJob(s)#L1602、#L1650、#L1696、#L1716 等整组暂停时传入null表示所有组恢复同理#L1739-#L1866关闭事件Shutdown流程中调用NotifySchedulerListenersShutdown#L780。此外JobStore 侧的信号器ISchedulerSignaler见 ISchedulerSignaler.cs与SchedulerSignalerImplSchedulerSignalerImpl.cs负责把TriggerFinalized、JobDeleted、TriggerInError/TriggersInError、SchedulerError等来自 JobStore 运行过程的事件转发给调度器并最终广播给监听器。也就是说凡是调度器会感知到的重大状态迁移几乎都有一条对应的监听器通知路径这为可观测性与运维自动化提供了统一入口。实战示例在 ASP.NET Core 中集成 SchedulerListener仓库自带的可运行示例Quartz.Examples.AspNetCore提供了最直观的落地参考1. 实现监听器SampleSchedulerListener.cs——得益于默认接口方法只需覆写关心的事件using Quartz.Listeners; namespace Quartz.Examples.AspNetCore; public class SampleSchedulerListener : ISchedulerListener { private readonly ILoggerSampleSchedulerListener logger; public SampleSchedulerListener(ILoggerSampleSchedulerListener logger) { this.logger logger; } public ValueTask SchedulerStarted(IScheduler scheduler, CancellationToken cancellationToken default) { logger.LogInformation(Observed start of scheduler {SchedulerName}, scheduler.SchedulerName); return default; } }2. 在 DI 配置中注册Startup.csservices.AddQuartz(q { // ... 其他调度器配置 ... // add some listeners q.AddSchedulerListenerSampleSchedulerListener(); q.AddJobListenerSampleJobListener(GroupMatcherJobKey.GroupEquals(jobKey.Group)); q.AddTriggerListenerSampleTriggerListener(); });SampleSchedulerListener的构造函数注入了ILoggerAddSchedulerListenerT()会通过 DI 容器解析并创建实例——这正是方式二中按类型注册的典型用法。启动应用后调度器启动时该监听器便会打印对应的调度器名称日志验证链路是否生效。典型应用场景基于接口语义与源码实现SchedulerListener 适合承担以下职责调度拓扑可观测性记录 Job/Trigger 的添加、移除、暂停、恢复全量变更形成审计日志健康告警SchedulerError捕获 JobStore 反复失败、Job 实例化失败等严重故障联动告警系统TriggerInError/TriggersInError可用于识别卡死在错误状态的 Trigger优雅停机与恢复编排SchedulerStarting/SchedulerShutdown通知驱动依赖调度器的组件做初始化/清理多调度器路由同一监听器服务多个调度器时通过回调第一参数scheduler区分来源这正是 ISchedulerListener.cs 注释所强调的设计意图触发生命周期收尾TriggerFinalizedTrigger 永不再触发后可做资源回收或业务补偿。小结SchedulerListener 是 Quartz.NET 中观察调度器全局状态的官方通道。相比 Job/Trigger 监听器它没有全局/非全局之分也没有 matcher 过滤——因为调度器级别的事件天然属于整个调度器。当前仓库版本将其演进为全异步、默认接口方法风格并扩展了TriggerInError、JobInterrupted(fireInstanceId)、SchedulerStarting/ShuttingDown、SchedulingDataCleared等细粒度回调无论走ListenerManager直接注册、QuartzBuilder依赖注入还是SchedulerEventPlugin配置装配最终都会汇入 ListenerManagerImpl.cs 的统一管理。理解这一层监听机制是构建可靠调度运维体系的关键一步。赞分享任务调度后端【免费下载链接】quartznetQuartz Enterprise Scheduler .NET项目地址https://gitcode.com/gh_mirrors/qu/quartznet点击查看免费下载相关推荐Doctrine ORM 事件系统完全指南生命周期事件、回调与监听器的深度解析Doctrine ORM 事件系统完全指南生命周期事件、回调与监听器的深度解析 导读 本文是 Doctrine ORM 事件系统的技术实战指南。Doctrin数据库ORM后端OpenHarmony-TPC/ImageKnife回调机制完整生命周期事件监听OpenHarmony TPC/ImageKnife回调机制完整生命周期事件监听 引言 在OpenHarmony应用开发中图像加载是高频且关键的操作。传统的OpenHarmony移动开发缓存Reflex 事件触发器Event Triggers完全指南从生命周期事件到全局键盘监听Reflex 事件触发器Event Triggers完全指南从生命周期事件到全局键盘监听 事件触发器Event Triggers是 Reflex 中连后端前端Web框架上一篇Vulnserver漏洞服务器如何快速上手缓冲区溢出学习完整指南下一篇IDM 激活脚本使用教程1 条命令冻结 30 天试用新手 3 分钟跑通创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考