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

.NET Core定时后台任务每日时段执行异常问题求助

问题分析与解决方案

一、核心问题排查

  1. 服务未自动启动:ASP.NET Core部署在IIS时,默认应用池会在闲置后休眠,必须有请求触发才会唤醒,这就是你需要调用控制器方法才启动服务的原因。
  2. Timer执行不稳定:当前Timer每小时执行一次,但服务器应用池回收、进程重启会导致Timer丢失,次日无法执行;同时当前逻辑在21-23点期间会重复执行多次,若需求是该时段内仅执行一次,逻辑也需调整。

二、稳定实现方案

1. 改用BackgroundService(规范的托管服务实现)

官方推荐的BackgroundService是IHostedService的抽象实现,自带生命周期管理,比手动实现更可靠:

public class TimedEmailService : BackgroundService
{
    private readonly ILogger<TimedEmailService> _logger;
    private DateTime _lastExecutedDate = DateTime.MinValue;

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

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("定时邮件服务启动");

        while (!stoppingToken.IsCancellationRequested)
        {
            var now = DateTime.Now;
            var today = now.Date;
            
            // 仅当日未执行过,且当前时间在21:00-23:59之间时执行
            if (now.TimeOfDay >= new TimeSpan(21, 0, 0) 
                && now.TimeOfDay <= new TimeSpan(23, 59, 0)
                && _lastExecutedDate.Date != today)
            {
                try
                {
                    await SendEmail();
                    _lastExecutedDate = now;
                    _logger.LogInformation("当日邮件发送完成");
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "邮件发送失败");
                }
            }

            // 每分钟检查一次,避免高频轮询
            await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
        }

        _logger.LogInformation("定时邮件服务停止");
    }

    private Task SendEmail()
    {
        // 你的邮件发送逻辑
        return Task.CompletedTask;
    }
}

2. 正确注册托管服务

在Program.cs中确保服务被注册:

builder.Services.AddHostedService<TimedEmailService>();

3. 解决IIS应用池休眠问题

部署在IIS时,需配置应用池防止闲置休眠:

  • 打开IIS管理器,找到目标应用池 → 高级设置
  • 设置**闲置超时(分钟)**为0(禁用闲置休眠)
  • 设置**定期时间间隔(分钟)**为0(禁用自动回收)
  • 将启动模式设为AlwaysRunning

4. 可选:使用Quartz.NET实现更可靠的定时任务

如果需要复杂规则、重试机制或持久化,推荐使用Quartz.NET:

  • 安装NuGet包:Quartz和Quartz.AspNetCore
  • 配置代码示例:
// Program.cs
builder.Services.AddQuartz(q =>
{
    q.UseMicrosoftDependencyInjectionJobFactory();

    // 注册邮件作业
    var jobKey = new JobKey("DailyEmailJob");
    q.AddJob<DailyEmailJob>(opts => opts.WithIdentity(jobKey));

    // 配置触发器:每日21:00执行一次
    q.AddTrigger(opts => opts
        .ForJob(jobKey)
        .WithIdentity("DailyEmailTrigger")
        .WithCronSchedule("0 0 21 ? * *")); // Cron表达式:每日21点整执行
});

// 启动Quartz服务
builder.Services.AddQuartzServer(options =>
{
    options.WaitForJobsToComplete = true;
});

// 邮件作业类
public class DailyEmailJob : IJob
{
    private readonly ILogger<DailyEmailJob> _logger;

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

    public async Task Execute(IJobExecutionContext context)
    {
        try
        {
            await SendEmail();
            _logger.LogInformation("邮件发送成功");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "邮件发送失败");
        }
    }

    private Task SendEmail()
    {
        // 你的邮件发送逻辑
        return Task.CompletedTask;
    }
}

三、关于停机时间的配置

如果服务需要定期维护,可以配置停机时间,但需注意:

  • 若使用IIS,可通过应用池的回收时间设置定期回收,但要避开21:00-23:59的执行时段
  • 若使用Quartz,可在作业中添加检查逻辑,跳过停机时段的执行
  • 若无维护需求,建议禁用自动回收,避免服务中断导致任务丢失

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 05:45:23