定时任务
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();
}
}最佳实践
- 幂等设计:任务可重复执行不影响结果
- 异常处理:记录异常日志,避免任务中断
- 执行超时:设置合理的执行超时时间
- 资源释放:任务完成后释放资源
相关文件
| 文件 | 说明 |
|---|---|
Program.cs | 调度服务注册配置 |
Youlai.Infrastructure/Jobs/ | Job 实现目录 |
