Skip to content

yuan-yp/TaskScheduler.NET

Repository files navigation

TaskScheduler - .NET 定时任务调度框架

一个基于 .NET 6 的轻量级定时任务调度框架,支持 Cron 表达式和依赖注入。

✨ 特性

  • Cron 表达式 - 灵活配置执行时间
  • 💉 依赖注入 - 完整的 DI 支持
  • 🎯 简单易用 - 基于接口,快速上手
  • 📝 日志记录 - 内置日志支持
  • 🔄 自动调度 - 任务自动重新安排

🚀 快速开始

1. 克隆项目

git clone <your-repo-url>
cd TaskScheduler

2. 配置连接信息

修改配置文件,填入你的实际配置:

数据库配置 - 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";
}

3. 运行项目

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点

⏰ Cron 表达式

格式:分 时 日 月 周

常用示例

* * * * *        # 每分钟
*/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;
    }
    
    // ... 实现接口
}

❓ 常见问题

Q: 如何调试单个任务?

// 在 Program.cs 的 Main 方法中
await scheduler.ExecuteTaskAsync("TaskName");

Q: 如何临时禁用任务?

public bool IsEnabled => false; // 设置为 false

Q: 如何访问数据库?

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();
        // ...
    }
}

Q: 任务执行失败会怎样?

任务失败会记录日志,然后自动安排下次执行,不影响其他任务。

⚙️ 配置说明

配置文件位置

所有配置都在 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;
}

🎯 最佳实践

  1. 单一职责 - 每个任务只做一件事
  2. 幂等性 - 任务可以安全地重复执行
  3. 异常处理 - 始终捕获并记录异常
  4. 取消支持 - 使用 CancellationToken
  5. 结构化日志 - 使用参数化日志
// ✅ 推荐
_logger.LogInformation("处理了 {Count} 条数据", count);

// ❌ 不推荐
_logger.LogInformation($"处理了 {count} 条数据");

📄 许可证

MIT License - 详见 LICENSE 文件

🤝 贡献

欢迎提交 Issue 和 Pull Request!


⭐ 如果觉得有用,请给个 Star!

About

C# .NET定时任务调度器

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages