如何让Quartz.NET在Windows服务中持续运行不自动关闭
解决Quartz.NET部署Windows服务后立即关闭的问题
问题现象
将Quartz.NET部署为Windows服务时,服务启动后立即关闭。Quartz DEBUG日志显示调度器创建后随即触发shutdown流程:
2025-06-02 09:24:55,889 [5] : Using object serializer: Quartz.Simpl.JsonObjectSerializer, Quartz.Serialization.Json 2025-06-02 09:24:55,921 [5] : TaskSchedulingThreadPool configured with max concurrency of 10 and TaskScheduler ThreadPoolTaskScheduler. 2025-06-02 09:24:55,937 [5] : Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl 2025-06-02 09:24:55,937 [5] : Quartz Scheduler created 2025-06-02 09:24:55,952 [5] : Registering Quartz Job Initialization Plug-in. 2025-06-02 09:24:55,968 [5] : Scheduler QuartzScheduler_$_NON_CLUSTERED shutting down. 2025-06-02 09:24:55,968 [5] : Scheduler QuartzScheduler_$_NON_CLUSTERED paused. 2025-06-02 09:24:55,983 [5] : Shutting down threadpool... 2025-06-02 09:24:55,983 [5] : Shutdown of threadpool complete. 2025-06-02 09:24:55,983 [5] : Scheduler QuartzScheduler_$_NON_CLUSTERED Shutdown complete.
问题根源
- 调度器未加载任务配置:原代码中创建
StdSchedulerFactory时未传入包含XML任务加载的配置集合,导致调度器无任务可执行,启动后自动关闭。 - 异步启动方式不当:
OnStart方法中使用Task.Run启动调度器,可能导致服务控制管理器提前判定启动完成,而调度器初始化未稳定完成。 - 代码拼写错误:
ServiveBase.Run应为ServiceBase.Run,会引发运行时错误。
修复方案
修正后的代码
Program.cs
using System.ServiceProcess; namespace YourNamespace { static class Program { static void Main() { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new MyWindowsService() }; ServiceBase.Run(ServicesToRun); // 修正拼写错误 } } }
MyWindowsService.cs
using System.ServiceProcess; using System.Collections.Specialized; using Quartz; using Quartz.Impl; public class MyWindowsService : ServiceBase { private IScheduler _scheduler; protected override void OnStart(string[] args) { // 同步初始化调度器,避免异步启动导致的生命周期问题 StartScheduler(); } private void StartScheduler() { // 初始化Quartz配置,包含XML任务加载插件 NameValueCollection props = new NameValueCollection { { "quartz.scheduler.instanceName", "MyScheduler" }, { "quartz.threadPool.type", "Quartz.Simpl.SimpleThreadPool" }, { "quartz.threadPool.threadCount", "5" }, { "quartz.jobStore.type", "Quartz.Simpl.RAMJobStore" }, { "quartz.plugin.jobInitializer.fileNames", "quartz_jobs.xml"}, { "quartz.plugin.jobInitializer.failOnFileNotFound", "true" }, // 强制检查XML文件存在 { "quartz.plugin.jobInitializer.scanInterval", "60" } // 可选:定期扫描XML变更 }; // 使用带配置的工厂创建调度器,确保加载XML任务 ISchedulerFactory schedulerFactory = new StdSchedulerFactory(props); _scheduler = schedulerFactory.GetScheduler().GetAwaiter().GetResult(); _scheduler.Start().GetAwaiter().GetResult(); } protected override void OnStop() { // 优雅关闭调度器,等待正在执行的任务完成 if (_scheduler != null) { _scheduler.Shutdown(waitForJobsToComplete: true).GetAwaiter().GetResult(); } } }
额外检查项
- 确保
quartz_jobs.xml的复制到输出目录属性设置为「如果较新则复制」或「始终复制」,避免服务运行时找不到文件。 - 检查Windows服务的运行账户权限:需具备读取XML文件和执行Job的权限。
- 验证
quartz_jobs.xml中的job-type格式正确(命名空间+类名,程序集名称),避免Job加载失败。
内容的提问来源于stack exchange,提问作者James Casement
相关产品推荐
相关产品推荐

