Skip to content

定时任务

youlai-aspnet 基于 .NET 内置的 IHostedService 或集成 Quartz.NET 实现定时任务调度。

调度方式

方式说明适用场景
IHostedService.NET 内置后台服务简单定时任务
Quartz.NET专业调度框架复杂调度场景
Hangfire可视化调度面板需要监控的任务

IHostedService 实现

后台服务

csharp
public class TimedHostedService : IHostedService, IDisposable
{
    private Timer? _timer;
    private readonly ILogger<TimedHostedService> _logger;

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

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("定时任务服务启动");
        _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));
        return Task.CompletedTask;
    }

    private void DoWork(object? state)
    {
        _logger.LogInformation("执行定时任务:{Time}", DateTime.Now);
        // 业务逻辑
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("定时任务服务停止");
        _timer?.Change(Timeout.Infinite, 0);
        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}

注册服务

csharp
// Program.cs
builder.Services.AddHostedService<TimedHostedService>();

Quartz.NET 集成

安装依赖

xml
<PackageReference Include="Quartz" Version="3.8.0" />
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.8.0" />

定义 Job

csharp
public class DataCleanupJob : IJob
{
    private readonly ILogger<DataCleanupJob> _logger;
    private readonly YoulaiDbContext _dbContext;

    public DataCleanupJob(ILogger<DataCleanupJob> logger, YoulaiDbContext dbContext)
    {
        _logger = logger;
        _dbContext = dbContext;
    }

    public async Task Execute(IJobExecutionContext context)
    {
        _logger.LogInformation("执行数据清理任务:{Time}", DateTime.Now);
        // 清理过期数据
        await Task.CompletedTask;
    }
}

配置调度

csharp
// Program.cs
builder.Services.AddQuartz(q =>
{
    q.UseMicrosoftDependencyInjectionJobFactory();

    var jobKey = new JobKey("DataCleanupJob");
    q.AddJob<DataCleanupJob>(opts => opts.WithIdentity(jobKey));

    q.AddTrigger(opts => opts
        .ForJob(jobKey)
        .WithIdentity("DataCleanupJob-trigger")
        .WithCronSchedule("0 0 2 * * ?")); // 每天凌晨 2 点执行
});

builder.Services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);

Cron 表达式

秒 分 时 日 月 周
*  *  *  *  *  *

示例:
0 0 2 * * ?      # 每天凌晨 2 点
0 */5 * * * ?    # 每 5 分钟
0 0 9-17 * * ?   # 每天 9-17 点整点
0 0 0 ? * MON    # 每周一零点

任务管理

手动触发

csharp
public class JobController : ControllerBase
{
    private readonly ISchedulerFactory _schedulerFactory;

    [HttpPost("jobs/{jobName}/trigger")]
    public async Task<IActionResult> TriggerJob(string jobName)
    {
        var scheduler = await _schedulerFactory.GetScheduler();
        await scheduler.TriggerJob(new JobKey(jobName));
        return Ok();
    }
}

任务状态查询

csharp
var scheduler = await _schedulerFactory.GetScheduler();
var jobKeys = await scheduler.GetJobKeys(GroupMatcher<JobKey>.AnyGroup());

foreach (var key in jobKeys)
{
    var triggers = await scheduler.GetTriggersOfJob(key);
    foreach (var trigger in triggers)
    {
        var state = await scheduler.GetTriggerState(trigger.Key);
        var nextFireTime = trigger.GetNextFireTimeUtc();
    }
}

最佳实践

  1. 幂等设计:任务可重复执行不影响结果
  2. 异常处理:记录异常日志,避免任务中断
  3. 执行超时:设置合理的执行超时时间
  4. 资源释放:任务完成后释放资源

相关文件

文件说明
Program.cs调度服务注册配置
Youlai.Infrastructure/Jobs/Job 实现目录

基于 MIT 许可发布