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

ASP.NET Core Web API发布IIS后Quartz后台任务失效求助

问题:ASP.NET Core部署IIS后Quartz.NET调度任务未执行

基于Quartz.NET开发的后台调度服务在本地运行正常,但发布至IIS服务器后,Swagger页面可正常访问,发布过程无异常,但后台调度任务完全无法执行。核心实现代码如下:

public class NotificationJob : IHostedService
{
    readonly ILogger<NotificationJob> _logger;

    public NotificationJob(ILogger<NotificationJob> logger)
    {
        _logger = logger;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Service started..!");

        await NotificationJob1();

        // ...
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Service stopped..!");
        return Task.CompletedTask;
    }

    private async Task NotificationJob1()
    {
        var schedulerFactory = new StdSchedulerFactory();
        var scheduler = await schedulerFactory.GetScheduler();
        await scheduler.Start();

        // Define the job
        var job = JobBuilder.Create<BackgroundWorkerJob>()
            .WithIdentity("BackgroundWorkerJob", "DefaultGroup")
            .Build();

        // Define multiple triggers with different time intervals
        var triggers = new List<ITrigger>
        {
//--------------------------------------- NOTIFICATION 0 ---------------------------------------- 

            TriggerBuilder.Create()
                .WithIdentity("BackgroundWorkerJobTrigger0", "DefaultGroup")
                .StartAt(DateBuilder.TodayAt(23,58,00)) // 2:19 PM Today
                .WithSimpleSchedule(x => x.WithIntervalInHours(24) // Repeat every 24 hours
                .RepeatForever())
                .Build(),
//--------------------------------------- NOTIFICATION 1  ---------------------------------------- 
            TriggerBuilder.Create()
                .WithIdentity("BackgroundWorkerJobTrigger1", "DefaultGroup")
                .StartAt(DateBuilder.TodayAt(23,59,0)) // 6:30 PM Today
                .WithSimpleSchedule(x => x.WithIntervalInHours(24) // Repeat every 24 hours
                .RepeatForever())
                .Build(),

//--------------------------------------- NOTIFICATION 2 ---------------------------------------- 
            TriggerBuilder.Create()
                .WithIdentity("BackgroundWorkerJobTrigger2", "DefaultGroup")
                .StartAt(DateBuilder.TodayAt(24,00, 0)) // 6:30 PM Today
                .WithSimpleSchedule(x => x.WithIntervalInHours(24) // Repeat every 24 hours
                .RepeatForever())
                .Build(),
//--------------------------------------- NOTIFICATION 3 ---------------------------------------- 
            TriggerBuilder.Create()
                .WithIdentity("BackgroundWorkerJobTrigger3", "DefaultGroup")
                .StartAt(DateBuilder.TodayAt(15,32, 0)) // 6:30 PM Today
                .WithSimpleSchedule(x => x.WithIntervalInHours(24) // Repeat every 24 hours
                .RepeatForever())
                .Build(),
   

            // Add more triggers as needed
        };

        // Schedule the job with multiple triggers
        await scheduler.ScheduleJob(job, triggers, true); // 'true' means to replace existing triggers if any
    }
}

解决方案

1. 调整IIS应用池核心配置

  • 将应用池启动模式设置为AlwaysRunning,避免IIS因闲置自动回收进程
  • 开启应用池预加载功能,确保站点启动时立即初始化后台服务
  • 确认应用池的.NET CLR版本设置为无托管代码(适用于ASP.NET Core 3.1及以上版本)

2. 改用Quartz.NET官方依赖注入方式

当前手动创建StdSchedulerFactory的方式容易在IIS进程回收时丢失调度上下文,建议通过DI注册Quartz服务:

// 在Program.cs中注册Quartz相关服务
builder.Services.AddQuartz(q =>
{
    // 使用.NET依赖注入管理Job实例
    q.UseMicrosoftDependencyInjectionJobFactory();
    
    // 注册后台执行的Job
    q.AddJob<BackgroundWorkerJob>(opts => opts.WithIdentity("BackgroundWorkerJob", "DefaultGroup"));
    
    // 为Job添加第一个触发器
    q.AddTrigger(opts => opts
        .ForJob("BackgroundWorkerJob", "DefaultGroup")
        .WithIdentity("BackgroundWorkerJobTrigger0", "DefaultGroup")
        .StartAt(DateBuilder.TodayAt(23, 58, 00))
        .WithSimpleSchedule(x => x.WithIntervalInHours(24).RepeatForever()));
    
    // 依次添加其他触发器(示例为Trigger1)
    q.AddTrigger(opts => opts
        .ForJob("BackgroundWorkerJob", "DefaultGroup")
        .WithIdentity("BackgroundWorkerJobTrigger1", "DefaultGroup")
        .StartAt(DateBuilder.TodayAt(23, 59, 00))
        .WithSimpleSchedule(x => x.WithIntervalInHours(24).RepeatForever()));
    
    // 注意:修正Trigger2的时间配置,24点应改为0点
    q.AddTrigger(opts => opts
        .ForJob("BackgroundWorkerJob", "DefaultGroup")
        .WithIdentity("BackgroundWorkerJobTrigger2", "DefaultGroup")
        .StartAt(DateBuilder.TodayAt(0, 00, 00))
        .WithSimpleSchedule(x => x.WithIntervalInHours(24).RepeatForever()));
});

// 注册Quartz托管服务,确保应用停止时等待任务完成
builder.Services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);

之后删除原NotificationJob中手动初始化调度器的代码,直接依赖Quartz的托管服务即可。

3. 修复时间配置错误

代码中DateBuilder.TodayAt(24,00,0)是无效参数,小时范围为0-23,需改为DateBuilder.TodayAt(0,00,0)表示午夜12点。

4. 排查进程回收与日志

  • 检查IIS应用池的回收规则,禁用不必要的定时回收,或调整回收时间至任务空闲时段
  • 补充日志输出:在BackgroundWorkerJob的Execute方法中记录执行日志,在调度初始化过程中添加调度器启动、触发器注册的日志,通过日志确认调度是否正常初始化
  • 确认服务器系统时间与本地一致,避免触发器启动时间设置偏差

5. 验证权限配置

确保IIS应用池的运行账号拥有执行Job业务逻辑所需的权限(如文件读写、数据库访问、第三方API调用等),如果使用Quartz持久化存储,需保证账号能访问对应存储资源。

内容的提问来源于stack exchange,提问作者oggy oggy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 21:27:41