Blog.Core 定时任务:动态添加与管理 Quartz 任务

Blog.Core 定时任务:动态添加与管理 Quartz 任务

【免费下载链接】Blog.Core 💖 ASP.NET Core 8.0 全家桶教程,前后端分离后端接口,vue教程姊妹篇,官方文档: 【免费下载链接】Blog.Core 项目地址: https://gitcode.com/gh_mirrors/bl/Blog.Core

引言:解决定时任务动态管理痛点

在企业级应用开发中,定时任务(Schedule Task)是不可或缺的组件,用于处理周期性数据同步、报表生成、系统维护等关键业务。传统定时任务实现方式存在三大痛点:

  • 硬编码问题:任务调度逻辑嵌入代码,修改需重新编译部署
  • 灵活性不足:无法动态调整任务执行周期、启停状态
  • 监控缺失:缺乏统一的任务状态管理和执行日志跟踪

ASP.NET Core 生态中的 Blog.Core 项目通过集成 Quartz.NET 框架,提供了一套完整的动态任务管理解决方案。本文将深入解析其实现原理,带你掌握在 Blog.Core 中如何实现任务的动态添加、启停控制、状态监控等高级功能。

核心架构:Quartz 任务管理系统设计

系统组件关系图

mermaid

核心组件说明

组件职责关键接口
ISchedulerCenter任务调度核心接口定义任务生命周期管理标准方法
SchedulerCenterServer调度实现类封装 Quartz.NET 调度器操作
TasksQz任务实体类存储任务配置信息(触发器类型、执行周期等)
TasksQzControllerAPI 控制器提供任务管理 RESTful 接口
IJobFactory任务实例工厂集成依赖注入容器,支持构造函数注入

关键实现:动态任务管理核心技术

1. 任务调度器初始化

SchedulerCenterServer 构造函数中完成调度器初始化,采用 IOC 容器管理 Quartz 实例:

private Task<IScheduler> GetSchedulerAsync()
{
    if (_scheduler != null)
        return this._scheduler;
    else
    {
        // 配置序列化器类型
        NameValueCollection collection = new NameValueCollection
        {
            { "quartz.serializer.type", "binary" },
        };
        StdSchedulerFactory factory = new StdSchedulerFactory(collection);
        return _scheduler = factory.GetScheduler();
    }
}

2. 任务添加核心逻辑

AddScheduleJobAsync 方法实现动态任务注册,支持两种触发器类型:

public async Task<MessageModel<string>> AddScheduleJobAsync(TasksQz tasksQz)
{
    // 1. 任务存在性检查
    JobKey jobKey = new JobKey(tasksQz.Id.ToString(), tasksQz.JobGroup);
    if (await _scheduler.Result.CheckExists(jobKey))
    {
        return new MessageModel<string> { 
            success = false, 
            msg = $"任务已存在:【{tasksQz.Name}】" 
        };
    }
    
    // 2. 设置时间参数
    DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(tasksQz.BeginTime, 1);
    DateTimeOffset endRunTime = DateBuilder.NextGivenSecondDate(tasksQz.EndTime, 1);
    
    // 3. 反射加载任务类型
    Assembly assembly = Assembly.Load(new AssemblyName(tasksQz.AssemblyName));
    Type jobType = assembly.GetType($"{tasksQz.AssemblyName}.{tasksQz.ClassName}");
    
    // 4. 创建任务详情
    IJobDetail job = new JobDetailImpl(
        tasksQz.Id.ToString(), 
        tasksQz.JobGroup, 
        jobType
    );
    job.JobDataMap.Add("JobParam", tasksQz.JobParams);
    
    // 5. 创建触发器 (根据类型选择 Cron/Simple)
    ITrigger trigger = tasksQz.TriggerType > 0 && CronExpression.IsValidExpression(tasksQz.Cron) 
        ? CreateCronTrigger(tasksQz) 
        : CreateSimpleTrigger(tasksQz);
    
    // 6. 调度任务
    await _scheduler.Result.ScheduleJob(job, trigger);
    return new MessageModel<string> { 
        success = true, 
        msg = $"【{tasksQz.Name}】添加成功" 
    };
}

3. 两种触发器实现

Cron 触发器 - 支持复杂时间表达式(如"0 0 12 * * ?"每天中午执行):

private ITrigger CreateCronTrigger(TasksQz sysSchedule)
{
    return TriggerBuilder.Create()
        .WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
        .StartAt(sysSchedule.BeginTime.Value)
        .EndAt(sysSchedule.EndTime.Value)
        .WithCronSchedule(sysSchedule.Cron)
        .ForJob(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
        .Build();
}

Simple 触发器 - 支持固定间隔执行(如每30秒执行一次):

private ITrigger CreateSimpleTrigger(TasksQz sysSchedule)
{
    var scheduleBuilder = sysSchedule.CycleRunTimes > 0 
        ? SimpleScheduleBuilder.RepeatSecondlyForever(sysSchedule.IntervalSecond)
            .WithRepeatCount(sysSchedule.CycleRunTimes - 1)
        : SimpleScheduleBuilder.RepeatSecondlyForever(sysSchedule.IntervalSecond);

    return TriggerBuilder.Create()
        .WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
        .StartAt(sysSchedule.BeginTime.Value)
        .EndAt(sysSchedule.EndTime.Value)
        .WithSchedule(scheduleBuilder)
        .Build();
}

实战指南:动态任务管理操作详解

任务管理 API 接口

TasksQzController 提供完整的任务管理 RESTful API:

接口方法功能请求参数示例
/api/TasksQz/AddPOST添加任务{"name":"数据同步任务","jobGroup":"sync","assemblyName":"Blog.Core.Tasks","className":"DataSyncJob","triggerType":1,"cron":"0 0/5 * * * ?","beginTime":"2025-01-01T00:00:00"}
/api/TasksQz/UpdatePUT更新任务同添加,含ID
/api/TasksQz/ChangeStatusPOST更改状态{"id":1,"status":1} (1:启用,0:禁用)
/api/TasksQz/ExecuteNowPOST立即执行{"id":1}
/api/TasksQz/GetTaskStatusGET获取状态?id=1

创建自定义任务步骤

  1. 创建任务类 - 实现 IJob 接口:
public class DataSyncJob : IJob
{
    private readonly ILogger<DataSyncJob> _logger;
    private readonly IDataService _dataService;
    
    // 支持依赖注入
    public DataSyncJob(ILogger<DataSyncJob> logger, IDataService dataService)
    {
        _logger = logger;
        _dataService = dataService;
    }
    
    public async Task Execute(IJobExecutionContext context)
    {
        _logger.LogInformation("数据同步任务开始执行");
        var jobParam = context.JobDetail.JobDataMap.GetString("JobParam");
        await _dataService.SyncData(jobParam);
        _logger.LogInformation("数据同步任务执行完成");
    }
}
  1. 注册任务到容器 - 在 Startup.cs 中配置:
services.AddTransient<DataSyncJob>();
  1. 通过 API 创建任务 - 调用 Add 接口,指定程序集和类名:
{
  "name": "用户数据同步",
  "jobGroup": "sync",
  "assemblyName": "Blog.Core.Tasks",
  "className": "DataSyncJob",
  "triggerType": 1,
  "cron": "0 0/30 * * * ?",
  "beginTime": "2025-01-01T00:00:00",
  "jobParams": "{\"source\":\"DB\",\"target\":\"ES\",\"table\":\"users\"}"
}

任务状态管理

SchedulerCenter 提供完整的任务生命周期控制:

操作方法说明
启动调度器StartScheduleAsync()启动整个调度系统
停止调度器StopScheduleAsync()停止所有任务调度
暂停任务PauseJob(TasksQz)暂停指定任务
恢复任务ResumeJob(TasksQz)恢复被暂停的任务
立即执行ExecuteJobAsync(TasksQz)无视调度规则立即执行一次
检查状态GetTaskStaus(TasksQz)获取任务当前状态(正常/暂停/完成等)

状态转换流程图:

mermaid

高级特性:任务监控与异常处理

任务执行状态监控

通过 GetTaskStaus 方法可获取任务详细状态信息:

public async Task<List<TaskInfoDto>> GetTaskStaus(TasksQz sysSchedule)
{
    var result = new List<TaskInfoDto>();
    JobKey jobKey = new JobKey(sysSchedule.Id.ToString(), sysSchedule.JobGroup);
    IJobDetail job = await _scheduler.Result.GetJobDetail(jobKey);
    
    if (job == null)
    {
        return new List<TaskInfoDto> {
            new TaskInfoDto {
                jobId = sysSchedule.Id.ToString(),
                jobGroup = sysSchedule.JobGroup,
                triggerStatus = "不存在"
            }
        };
    }
    
    var triggers = await _scheduler.Result.GetTriggersOfJob(jobKey);
    foreach (var trigger in triggers)
    {
        var triggerStatus = await _scheduler.Result.GetTriggerState(trigger.Key);
        result.Add(new TaskInfoDto {
            jobId = job.Key.Name,
            jobGroup = job.Key.Group,
            triggerId = trigger.Key.Name,
            triggerGroup = trigger.Key.Group,
            triggerStatus = GetTriggerState(triggerStatus.ToString())
        });
    }
    return result;
}

异常处理机制

任务执行异常处理策略:

  1. 日志记录:通过 ILogger 记录详细异常信息
  2. 重试机制:配置触发器的失败重试策略
  3. 报警通知:集成企业微信/邮件报警系统
// 在 Job 实现中添加异常处理
public async Task Execute(IJobExecutionContext context)
{
    try
    {
        // 业务逻辑实现
        await _dataService.SyncData();
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, $"任务执行失败: {ex.Message}");
        // 可根据需要抛出异常让 Quartz 处理重试
        throw new JobExecutionException(ex) { RefireImmediately = true };
    }
}

性能优化:大规模任务调度最佳实践

当系统中存在大量定时任务时,需考虑以下优化策略:

1. 任务分组与资源隔离

通过 JobGroup 对任务进行逻辑分组,避免资源竞争:

// 不同业务域使用不同分组
var reportTasks = new TasksQz {
    Name = "销售报表生成",
    JobGroup = "report_sales",  // 销售报表组
    // 其他参数...
};

var syncTasks = new TasksQz {
    Name = "数据同步",
    JobGroup = "data_sync",     // 数据同步组
    // 其他参数...
};

2. 任务优先级设置

通过设置任务优先级确保关键任务优先执行:

IJobDetail job = JobBuilder.Create<CriticalJob>()
    .WithIdentity("criticalJob", "system")
    .RequestRecovery(true)  // 系统崩溃后恢复执行
    .StoreDurably(true)     // 即使无触发器也保留任务
    .Build();
    
ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("criticalTrigger", "system")
    .StartNow()
    .WithPriority(10)       // 设置高优先级
    .WithCronSchedule("0 0 1 * * ?")
    .Build();

3. 集群部署注意事项

在多实例部署环境中,需配置 Quartz 集群模式:

// 集群配置示例 (appsettings.json)
"Quartz": {
  "scheduler": {
    "instanceName": "BlogCoreScheduler"
  },
  "threadPool": {
    "type": "Quartz.Simpl.SimpleThreadPool, Quartz",
    "threadCount": "10",
    "threadPriority": "Normal"
  },
  "jobStore": {
    "type": "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz",
    "driverDelegateType": "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz",
    "tablePrefix": "QRTZ_",
    "useProperties": "false",
    "dataSource": "default",
    "clusterCheckinInterval": "15000"
  },
  "dataSource": {
    "default": {
      "connectionString": "Server=.;Database=QuartzDB;User Id=sa;Password=123456;",
      "provider": "SqlServer"
    }
  }
}

总结与扩展

Blog.Core 项目通过 Quartz.NET 实现的动态任务管理系统,完美解决了传统定时任务的刚性问题,其核心优势在于:

  1. 全动态化:任务配置存储于数据库,支持运行时动态调整
  2. IOC 集成:通过自定义 JobFactory 实现任务类的依赖注入
  3. 完整生命周期:提供从创建到销毁的全流程任务管理
  4. 多触发器支持:同时支持 Cron 和 Simple 两种调度模式

未来扩展方向:

  • 可视化管理界面:开发 Web 控制台实现任务图形化管理
  • 执行日志分析:集成 ELK 栈实现任务执行日志集中分析
  • 智能调度:基于系统负载自动调整任务执行频率

通过本文的学习,你已经掌握了 Blog.Core 中动态任务管理的核心原理和使用方法。这套方案不仅适用于 Blog.Core 项目,也可作为 ASP.NET Core 定时任务最佳实践参考,帮助你构建更灵活、更可靠的企业级定时任务系统。

【免费下载链接】Blog.Core 💖 ASP.NET Core 8.0 全家桶教程,前后端分离后端接口,vue教程姊妹篇,官方文档: 【免费下载链接】Blog.Core 项目地址: https://gitcode.com/gh_mirrors/bl/Blog.Core

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值