一个基于 .NET 6 的轻量级定时任务调度框架,支持 Cron 表达式和依赖注入。
- ⏰ Cron 表达式 - 灵活配置执行时间
- 💉 依赖注入 - 完整的 DI 支持
- 🎯 简单易用 - 基于接口,快速上手
- 📝 日志记录 - 内置日志支持
- 🔄 自动调度 - 任务自动重新安排
git clone <your-repo-url>
cd TaskScheduler
修改配置文件,填入你的实际配置:
数据库配置 - TaskScheduler.Infrastructure/Configuration/DatabaseConfig.cs
public static class DatabaseConfig
{
public static string ConnectionString { get; set; } =
"Data Source=YOUR_SERVER/SERVICE;User Id=USER;password=PASSWORD";
}
API配置 - TaskScheduler.Infrastructure/Configuration/ApiConfig.cs
public static class ApiConfig
{
public static string FeishuWebhookUrl { get; set; } =
"https://open.feishu.cn/open-apis/bot/v2/hook/YOUR_WEBHOOK";
}
cd TaskScheduler.Console
dotnet run
using Microsoft.Extensions.Logging;
using TaskScheduler.Core;
namespace TaskScheduler.Tasks;
public class MyTask : ITask
{
private readonly ILogger<MyTask> _logger;
public MyTask(ILogger<MyTask> logger)
{
_logger = logger;
}
public string TaskName => "MyTask";
public string Description => "我的任务";
public bool IsEnabled => true;
public string CronExpression => "0 9 * * *"; // 每天早上9点
public async Task<TaskResult> ExecuteAsync(CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("任务开始执行...");
// 你的业务逻辑
await Task.Delay(100, cancellationToken);
return new TaskResult { IsSuccess = true, Message = "执行成功" };
}
catch (Exception ex)
{
_logger.LogError(ex, "执行失败");
return new TaskResult { IsSuccess = false, Exception = ex };
}
}
}
步骤1:创建服务接口和实现
// TaskScheduler.Infrastructure/Services/EmailService.cs
public interface IEmailService
{
Task<bool> SendEmailAsync(string to, string subject, string body);
}
public class EmailService : IEmailService
{
private readonly ILogger<EmailService> _logger;
public EmailService(ILogger<EmailService> logger)
{
_logger = logger;
}
public async Task<bool> SendEmailAsync(string to, string subject, string body)
{
_logger.LogInformation("发送邮件到 {To}", to);
// 实现邮件发送逻辑
await Task.Delay(100);
return true;
}
}
步骤2:在 Program.cs 中注册服务
services.AddScoped<IEmailService, EmailService>();
步骤3:在任务中使用服务
public class WeeklyReportTask : ITask
{
private readonly ILogger<WeeklyReportTask> _logger;
private readonly IEmailService _emailService;
private readonly IFeishuService _feishuService;
// 通过构造函数注入服务
public WeeklyReportTask(
ILogger<WeeklyReportTask> logger,
IEmailService emailService,
IFeishuService feishuService)
{
_logger = logger;
_emailService = emailService;
_feishuService = feishuService;
}
public string TaskName => "WeeklyReportTask";
public string Description => "周报任务";
public bool IsEnabled => true;
public string CronExpression => "0 9 * * 1"; // 每周一早上9点
public async Task<TaskResult> ExecuteAsync(CancellationToken cancellationToken = default)
{
// 使用注入的服务
await _emailService.SendEmailAsync("admin@example.com", "周报", "...");
await _feishuService.SendMessageAsync("周报", "...");
return new TaskResult { IsSuccess = true };
}
}
步骤4:注册任务
// 在 Program.cs 的 ConfigureServices 中
services.AddTransient<WeeklyReportTask>();
// 在 RegisterTasks 方法中
scheduler.AddTask(serviceProvider.GetRequiredService<WeeklyReportTask>());
在 Program.cs
中:
// 1. 注册服务
services.AddTransient<MyTask>();
// 2. 添加到调度器
scheduler.AddTask(serviceProvider.GetRequiredService<MyTask>());
项目包含 6 个示例任务,展示不同的使用场景:
任务 | 说明 | 执行时间 |
---|---|---|
HelloWorldTask | 最简单的示例 | 每分钟 |
DataSyncTask | 数据同步示例 | 每天凌晨2点 |
DailyReportTask | 每日报表(使用飞书服务) | 每天早上9点 |
HealthCheckTask | 系统健康检查 | 每5分钟 |
CleanupTask | 清理过期数据 | 每天凌晨3点 |
WeeklyReportTask | 周报(展示多服务使用) | 每周一早上9点 |
格式:分 时 日 月 周
* * * * * # 每分钟
*/5 * * * * # 每5分钟
0 * * * * # 每小时
0 2 * * * # 每天凌晨2点
0 9 * * * # 每天早上9点
0 9 * * 1 # 每周一早上9点
0 9 * * 1-5 # 工作日早上9点
0 0 1 * * # 每月1号凌晨
30 8,12,17 * * * # 每天8:30、12:30、17:30
*
- 任意值,
- 列举多个值(如1,3,5
)-
- 范围(如1-5
)/
- 步长(如*/5
表示每5个单位)
TaskScheduler/
├── TaskScheduler.Console/ # 控制台入口
│ └── Program.cs # 配置DI和注册任务
├── TaskScheduler.Core/ # 核心调度逻辑
│ ├── ITask.cs # 任务接口
│ ├── ITaskScheduler.cs # 调度器接口
│ └── TaskScheduler.cs # 调度器实现
├── TaskScheduler.Infrastructure/ # 基础设施
│ ├── Configuration/ # 📝 配置类目录
│ │ ├── DatabaseConfig.cs # 数据库配置
│ │ ├── ApiConfig.cs # API配置
│ │ └── README.md # 配置说明
│ ├── DataAccess/ # 数据访问
│ │ └── SqlSugarContext.cs
│ └── Services/ # 服务层
│ ├── FeishuService.cs # 飞书通知
│ └── EmailService.cs # 邮件服务
└── TaskScheduler.Tasks/ # 任务实现
├── HelloWorldTask.cs # 基础示例
├── DataSyncTask.cs # 数据同步
├── DailyReportTask.cs # 每日报表
├── HealthCheckTask.cs # 健康检查
├── CleanupTask.cs # 数据清理
└── WeeklyReportTask.cs # 周报(服务示例)
- .NET 6.0 - 开发框架
- Cronos - Cron 表达式解析
- SqlSugar - ORM(可选)
- Microsoft.Extensions.* - DI、日志、主机
// Singleton - 全局单例
services.AddSingleton<ITaskScheduler, Core.TaskScheduler>();
services.AddSingleton<SqlSugarContext>();
// Scoped - 每次请求创建
services.AddScoped<IFeishuService, FeishuService>();
services.AddScoped<IEmailService, EmailService>();
// Transient - 每次使用创建新实例
services.AddTransient<MyTask>();
任务支持构造函数注入任意已注册的服务:
public class MyTask : ITask
{
private readonly ILogger<MyTask> _logger;
private readonly IEmailService _emailService;
private readonly SqlSugarContext _dbContext;
private readonly IHttpClientFactory _httpClientFactory;
public MyTask(
ILogger<MyTask> logger,
IEmailService emailService,
SqlSugarContext dbContext,
IHttpClientFactory httpClientFactory)
{
_logger = logger;
_emailService = emailService;
_dbContext = dbContext;
_httpClientFactory = httpClientFactory;
}
// ... 实现接口
}
// 在 Program.cs 的 Main 方法中
await scheduler.ExecuteTaskAsync("TaskName");
public bool IsEnabled => false; // 设置为 false
public class MyTask : ITask
{
private readonly SqlSugarContext _dbContext;
public MyTask(SqlSugarContext dbContext)
{
_dbContext = dbContext;
}
public async Task<TaskResult> ExecuteAsync(CancellationToken ct)
{
var data = await _dbContext.Db.Queryable<YourTable>()
.Where(x => x.Status == 1)
.ToListAsync();
// ...
}
}
任务失败会记录日志,然后自动安排下次执行,不影响其他任务。
所有配置都在 TaskScheduler.Infrastructure/Configuration/
目录下:
配置文件 | 说明 |
---|---|
DatabaseConfig.cs |
数据库连接配置 |
ApiConfig.cs |
API和第三方服务配置 |
DatabaseConfig.cs
public static class DatabaseConfig
{
// 数据库连接字符串
public static string ConnectionString { get; set; } =
"Data Source=192.168.1.100/ORCL;User Id=admin;password=123456";
// 是否启用SQL日志
public static bool EnableSqlLog { get; set; } = true;
}
ApiConfig.cs
public static class ApiConfig
{
// 飞书机器人Webhook
public static string FeishuWebhookUrl { get; set; } =
"https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxx";
// 外部API地址
public static string ApiBaseUrl { get; set; } = "https://api.example.com";
// API超时时间
public static int ApiTimeout { get; set; } = 30;
}
- 单一职责 - 每个任务只做一件事
- 幂等性 - 任务可以安全地重复执行
- 异常处理 - 始终捕获并记录异常
- 取消支持 - 使用
CancellationToken
- 结构化日志 - 使用参数化日志
// ✅ 推荐
_logger.LogInformation("处理了 {Count} 条数据", count);
// ❌ 不推荐
_logger.LogInformation($"处理了 {count} 条数据");
MIT License - 详见 LICENSE 文件
欢迎提交 Issue 和 Pull Request!
⭐ 如果觉得有用,请给个 Star!