You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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.

问题根源

  1. 调度器未加载任务配置:原代码中创建StdSchedulerFactory时未传入包含XML任务加载的配置集合,导致调度器无任务可执行,启动后自动关闭。
  2. 异步启动方式不当:OnStart方法中使用Task.Run启动调度器,可能导致服务控制管理器提前判定启动完成,而调度器初始化未稳定完成。
  3. 代码拼写错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 23:17:05