Quartz 任务调度

Quartz.NET 是一个功能强大的开源任务调度库,广泛应用于 .NET 平台,用于定时执行任务。无论是简单的定时任务,还是复杂的调度需求,Quartz.NET 都能轻松应对。

官网:http://www.quartz-scheduler.net/

使用场景

  • 定时发送邮件:例如,每天定时发送报告邮件。
  • 定时备份数据库:例如,每天凌晨自动备份数据库。
  • 定时生成报表:例如,每月初生成上个月的销售报表。
  • 定时清理缓存:例如,每隔一段时间清理过期缓存。

主要组件

  1. Scheduler(调度器) :负责触发任务的核心组件。
  2. Job(任务) :执行特定操作的类,必须实现 IJob​ 接口。
  3. Trigger(触发器) :定义任务的执行时间。常见的触发器有 SimpleTrigger​(简单重复间隔)和 CronTrigger​(基于 cron 表达式的复杂调度)。
  4. JobDetail(任务详情) :包含任务执行所需的所有信息,如任务类和关联的作业数据。

基本用法

通过 NuGet 安装

  1. 打开 Visual Studio 并加载你的项目。
  2. 右键点击项目名称,选择“管理 NuGet 包”。
  3. 在 NuGet 包管理器中搜索“Quartz”,选择合适的版本,点击“安装”。

实现任务类

首先,创建一个实现了 IJob 接口的类。该接口包含 Execute 方法,任务运行时会调用此方法。

using Quartz;
using System;
using System.Threading.Tasks;

namespace QuartzExample
{
    [DisallowConcurrentExecution] // 禁止并发执行
    public class MailJobTest : IJob
    {
        public async Task Execute(IJobExecutionContext context)
        {
            try
            {
                Console.WriteLine("邮箱开始调度");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"定时器异常: {ex.Message}");
            }
        }
    }
}

启动调度

接下来,实例化并启动调度程序,并调度要执行的作业。

using Quartz;
using Quartz.Impl;
using System.Threading.Tasks;

namespace QuartzExample
{
    public class QuartzScheduler
    {
        private IScheduler _scheduler;

        public async Task StartScheduler()
        {
            // 创建调度器实例
            var factory = new StdSchedulerFactory();
            _scheduler = await factory.GetScheduler();
            await _scheduler.Start();

            // 创建任务
            var job = JobBuilder.Create<MailJobTest>()
                .WithIdentity("MailJob", "MailGroup")
                .Build();

            // 创建触发器
            var trigger = TriggerBuilder.Create()
                .WithIdentity("MailTrigger", "MailTriggerGroup")
                .WithCronSchedule("0/5 * * * * ?") // 每5秒执行一次
                .Build();

            // 调度任务
            await _scheduler.ScheduleJob(job, trigger);
        }

        public async Task StopScheduler()
        {
            if (_scheduler != null)
            {
                await _scheduler.Shutdown();
            }
        }
    }
}

调用示例

using System;
using System.Threading.Tasks;

namespace QuartzExample
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var quartzScheduler = new QuartzScheduler();
            await quartzScheduler.StartScheduler();

            Console.WriteLine("按任意键停止调度...");
            Console.ReadKey();

            await quartzScheduler.StopScheduler();
        }
    }
}

取消任务调度

// 关闭
scheduler1.Shutdown().Wait();

耗时任务处理

对于耗时较长的任务,可以使用 [DisallowConcurrentExecution]​ 特性,确保任务在上一次执行完成后才会开始下一次执行。

[DisallowConcurrentExecution]
public class LongRunningJob : IJob
{
    public async Task Execute(IJobExecutionContext context)
    {
        // 模拟耗时操作
        await Task.Delay(5000);
        Console.WriteLine("耗时任务完成");
    }
}

封装 ​ExQuartz 方法到类中

为了更好地组织代码并提高可维护性,我们可以将 ExQuartz​ 方法封装到一个类中。以下是封装后的 QuartzScheduler​ 类,同时考虑了 scheduler​ 的存储和访问。

QuartzScheduler 类

using Quartz;
using Quartz.Impl;
using System.Threading.Tasks;

namespace UploadLogiData.Quartzs
{
    /// <summary>
    /// 封装了 ExLogiQuartz 方法和对 scheduler 的访问
    /// </summary>
    public class QuartzScheduler
    {
        /// <summary>
        /// 调度器实例
        /// </summary>
        private IScheduler _scheduler;

        /// <summary>
        /// 静态定义主窗体(假设 Form1 是主窗体)
        /// </summary>
        public static Form1 Form { get; set; }

        /// <summary>
        /// 启动调度器并安排任务
        /// </summary>
        public async Task ExLogiQuartz()
        {
            Form.DisplayListboxMsg("检测任务启动!");

            // 创建调度器实例
            var factory = new StdSchedulerFactory();
            _scheduler = await factory.GetScheduler();
            await _scheduler.Start();

            // 创建第一个任务:LogiDownloadJob,每5秒执行一次
            var job1 = JobBuilder.Create<LogiDownloadJob>()
                .WithIdentity("LogiJob", "LogiGroup")
                .Build();
            var trigger1 = TriggerBuilder.Create()
                .WithIdentity("LogiTrigger", "LogiTriggerGroup")
                .WithCronSchedule("0/5 * * * * ?") // 每5秒执行一次
                .Build();
            await _scheduler.ScheduleJob(job1, trigger1);

            // 创建第二个任务:MailJobTest,每天下午3点10分执行一次
            var job2 = JobBuilder.Create<MailJobTest>()
                .WithIdentity("MailJob", "MailGroup")
                .Build();
            var trigger2 = TriggerBuilder.Create()
                .WithIdentity("MailTrigger", "MailTriggerGroup")
                .WithCronSchedule("0 10 15 * * ?") // 每天下午3点10分执行一次
                .Build();
            await _scheduler.ScheduleJob(job2, trigger2);
        }

        /// <summary>
        /// 获取调度器实例
        /// </summary>
        public IScheduler Scheduler => _scheduler;

        /// <summary>
        /// 关闭调度器
        /// </summary>
        public async Task ShutdownScheduler()
        {
            if (_scheduler != null)
            {
                await _scheduler.Shutdown();
            }
        }
    }
}

调用示例

以下是使用 QuartzScheduler​ 类的示例代码:

using System;
using System.Threading.Tasks;

namespace UploadLogiData
{
    class Program
    {
        public static async Task Main(string[] args)
        {
            // 初始化主窗体(假设 Form1 是主窗体)
            QuartzScheduler.Form = new Form1();

            // 创建 QuartzScheduler 实例
            var quartzScheduler = new QuartzScheduler();

            // 启动调度器并安排任务
            await quartzScheduler.ExLogiQuartz();

            Console.WriteLine("调度器已启动,按任意键关闭调度器...");
            Console.ReadKey();

            // 关闭调度器
            await quartzScheduler.ShutdownScheduler();
            Console.WriteLine("调度器已关闭。");
        }
    }
}

Cron 表达式

表达式格式

Quartz.NET 使用 Cron 表达式来定义复杂的调度规则。Cron 表达式由7个字段组成:秒、分、时、日、月、星期、年(可选)。

字段名 允许的值 允许的特殊字符
0-59 , - * /
0-59 , - * /
小时 0-23 , - * /
1-31 , - * ? / L W C
1-12 或 JAN-DEC , - * /
星期 1-7 或 SUN-SAT , - * ? / L C #
年(可选) 空或 1970-2099 , - * /

表达式例子

表达 含义
0 0 12 * * ? 每天中午12点(中午)触发
0 15 10 ? * * 每天上午10:15触发
0 15 10 * * ? 每天上午10:15触发
0 15 10 * * ? * 每天上午10:15触发
0 15 10 * * ? 2005 2005年期间,每天上午10:15触发
0 * 14 * * ? 每天从下午2点开始,直到下午2:59结束,每分钟触发一次
0 0/5 14 * * ? 每天从下午2点开始,直到下午2:55,每5分钟触发一次
0 0/5 14,18 * * ? 每天从下午2点开始到下午2:55结束,每5分钟触发一次,并且每天下午6点开始到下午6:55结束,每5分钟触发一次
0 0-5 14 * * ? 每天从下午2点开始,直到下午2:05结束,每分钟触发一次
0 10,44 14 ? 3 WED 3月的每个星期三下午2:10和2:44 pm触发。
0 15 10 ? * MON-FRI 每个星期一,星期二,星期三,星期四和星期五的上午10:15触发
0 15 10 15 * ? 每个月的15日上午10:15触发
0 15 10 L * ? 每个月的最后一天上午10:15触发
0 15 10 L-2 * ? 每个月的倒数第二个上午10:15触发
0 15 10 ? * 6L 每个月的最后一个星期五上午10:15触发
0 15 10 ? * 6L 每个月的最后一个星期五上午10:15触发
0 15 10 ? * 6L 2002-2005 在2002、2003、2004和2005年的每个月的最后一个星期五上午10:15触发
0 15 10 ? * 6#3 每个月的第三个星期五上午10:15触发
0 0 12 1/5 * ? 从每月的第一天开始,每月每5天在中午12点(中午)触发。
0 11 11 11 11 ? 每年11月11日上午11:11触发。
0 * * * * ? 每1分钟整点触发一次
0 0 * * * ? 每天每1小时整点触发一次
0 0 10 * * ? 每天10点触发一次
0 2 9 * * ? // 每天9点02分执行一次
0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发 
0 30 9 1 * ? 每月1号上午9点半
0 15 10 15 * ? 每月15日上午10:15触发
*/5 * * * * ? 每隔5秒执行一次
0 */1 * * * ? 每隔1分钟执行一次
0 0 5-15 * * ? 每天5-15点整点触发
0 0/3 * * * ? 每三分钟触发一次
0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发 
0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
0 0 10,14,16 * * ? 每天上午10点,下午2点,40 0 12 ? * WED 表示每个星期三中午120 0 17 ? * TUES,THUR,SAT 每周二、四、六下午五点
0 10,44 14 ? 3 WED 每年三月的星期三的下午2:102:44触发 
0 15 10 ? * MON-FRI 周一至周五的上午10:15触发
0 0 23 L * ? 每月最后一天23点执行一次
0 15 10 L * ? 每月最后一日的上午10:15触发 
0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发 
0 15 10 * * ? 2005 2005年的每天上午10:15触发 
0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发 
0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发

posted @   少年。  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~
点击右上角即可分享
微信分享提示