关于Quartz .NET(V3.0.7)的简要说明

摘要:
在示例中,RepeatForever()用于指示重复次数是无限的,或者可以使用WithRepeatCount()设置重复次数。这里有一个细节问题。例如,将执行时间设置为三次,WithRepeatCount。请注意,它实际上将执行四次。2.3执行Quartz任务有许多接口。NET在一天的固定时间。第一个例子是最基本的方法。下面的代码示例将被简化。

目录
shanzm-2020年3月25日 21:28:09

0. 任务调度

比如说,财务系统需要在每个月初生成上一个月的财务报表。

比如说,每天或每周固定时间对数据库更新。

比如说,每天定时发送邮件。

这些需要在某个预定的时间点周期性的执行某个特定的任务的功能(也就是任务调度),可以使用任务调度框架——Quartz .NET

Quartz.NET是一个开源的任务调度框架(作业调度框架),是从Java移植过来的,使用较为广泛!


1. Quartz .NET

1.1 基本概念

调度器(Scheduler):存放触发器和定时任务,根据触发器执行定时任务

触发器(Trigger):决定执行时间,执行间隔,运行次数,故触发器用来告诉调度程序作业什么时候触发

任务(Job):需要定时或是周期性执行的任务

使用流程:

创建调度器-->创建任务-->创建触发器-->Job和Trigger注册到调度器-->启动调度器;

1.2 主要接口和对象

接口/类作用
IScheduler调度器接口
IJob任务接口,将需要定时执行的方法实现在该接口的Excute方法中
IJobDetail用于定义Job的实例
ITrigger触发器接口
JobBuilder任务构造者:用于创建任务实例
TriggerBuilder触发器构造者:用于创建触发器实例
JobDetailImpl实现了IJobDetail类
JobKey任务名
TriggerKey触发器名

其中触发器的类型

触发器最常用的主要有两种:

SimpleTrigger:用于指定任务重复执行的时间间隔

IMutableTrigger:用于指定任务重复执行的具体时间


2. 使用示例

2.0 准备工作

①安装Quartz程序包

当前时间:2020年3月18日 23:20:59,最新版本的Quartz.NET为3.0.7

每次的版本的变化,API变化都好大,所以在这里注明当前的使用版本!

建议使用最新版本,新版本都是异步方法实现的。

NuGet:Install-Package Quartz -Version 3.0.7

②新建TestJob.cs
实现IJob接口

public class TestJob : IJob
{
    public async Task Execute(IJobExecutionContext context)
    {
        await Task.Run(() => Console.WriteLine($"{DateTime.Now}:执行任务了……"));
    }
}

2.1 每间隔一定时间间隔执行一次任务

//间隔5s重复一次执行指定的任务
public static async void WithInterval()
{
    //-------1.准备调度者
    ISchedulerFactory factory = new StdSchedulerFactory(); //创建调度器工厂
    IScheduler scheduler = await factory.GetScheduler(); //创建调度者

    //-------2.准备任务
    JobBuilder jobBuilder = JobBuilder.Create<TestJob>();//创建任务构造者:JobBuilder
    IJobDetail job1 = jobBuilder.Build();//创建任务

    //-------3.准备触发器
    TriggerBuilder triggerBuilder = TriggerBuilder.Create()
    .StartNow()//立即生效
    .WithSimpleSchedule(x=>x.WithIntervalInSeconds(5)
    .RepeatForever());  //创建触发器构造者:TriggerBuilder
    ISimpleTrigger trigger = triggerBuilder.WithIdentity("trigger1","group2").Build() as ISimpleTrigger;//创建触发器

    //-------4.将任务与触发器添加到调度器中
    await scheduler.ScheduleJob(job1, trigger);
    await scheduler.Start();//开始执行
}
        

【代码说明】

  • 示例中使用的而是ISimpleTrigger类型的触发器,可以精准的设置任务重复的时间间隔。

  • 其中的触发器构造者中的

    triggerBuilder.StartNow()表示触发器立即生效

    triggerBuilder.StartAt(DateTimeOffset startTimeUtc)设置触发器生效的时间

    triggerBuilder.EndAt(DateTimeOffset startTimeUtc)设置触发器失效的时间

  • 其中使用WithIntervalInSeconds(5)表示每五秒触发一次任务

    其他的一些按照小时和天的做间隔,以及明确触发次数的方法都简单明确,根据VS的智能提示即可了解,不一一列举于此!

  • 示例中使用RepeatForever()表示重复无穷次,还是可以使用WithRepeatCount()设置重复的次数的。

    这里有一个细节问题,比如说,设置执行三次,WithRepeatCount(3),但是注意实际会执行4次


2.3 某天的固定时间点执行任务

Quartz.NET的接口比较繁多,第一个示例中是使用的最基础的方法,下面代码示例将换一种简写的方式。

//每天按照指定的时间点执行任务
public static async void AtHourAndMinute()
{
    //创建调度器
    IScheduler scheduler = await new StdSchedulerFactory().GetScheduler();
    //创建任务
    //JobDetailImpl job1 = new JobDetailImpl("TestJob1", "group1", typeo(TestJob))//JobDetailImpl是IJobDetail的实现类
    //等价于:
    IJobDetail job1 = JobBuilder.Create<TestJob>().WithIdentity("Testjob1""group1").Build();
    //创建触发器
    IMutableTrigger trigger2job1 = CronScheduleBuilder.DailyAtHourAndMinut(03, 50).Build();//每天更具某时间点重复触发任务
    //将任务和触发器添加到调度器中
    trigger2job1.Key = new TriggerKey("trigger1");//注意一定要给触发器命名
    await scheduler.ScheduleJob(job1, trigger2job1);
    //开始执行调度者
    await scheduler.Start();
}

【代码说明】

  • 示例中使用的是IMutableTrigger类型的触发器

  • 通过CronScheduleBuilder类的静态方法可以设置触发的具体的某一日

    设置触发时间为每天的某时某分DailyAtHourAndMinut(03, 50)

    设置触发时间是一周中的哪几天中的几时几分AtHourAndMinuteOnGivenDaysOfWeek(int hour , int min, params DayOfWeek[] daysOfWeek)

    设置触发时间是每月中某天某时某分CronScheduleBuilder.MonthlyOnDayAndHourAndMinute(int dayOfMonth, int hour, int min).Build()

  • 封装好的一些方法还是有一定局限的(但是我自己够用的了),关于其他的一些复杂的周期任务,都是可以使用cron expression,使用cron expression可以定义你能想到的所有触发时间和周期

    cron expression什么样?怎么用?例如设置触发的时间是:每年每月的2点18分40秒CronScheduleBuilder.CronSchedule("40 18 2 ? * * *").WithIdentity("trigger1").Build();

    关于cron expression写起来还是有点麻烦的,可以使用一些在线生成器为我们自动的生成期望的表达式。

    推荐:Cron Expression Generator


2.4 封装整个定时任务,并给任务传递参数

前面的示例为了简洁的表示Quartz.NET的一些API的使用,

项目中都是把为定时任务,整个的操作流程封装在一个静态方法中,存放在我们自定义的Job类中

做一个简单的示例:定时发送短信。

自定义Job,实现IJob接口,同时把创建调度器对象,创建触发器和任务封装于其中,作为一个静态方法

class TestJob2 : IJob
{
    public async Task Execute(IJobExecutionContext context)
    {
        try
            {
                JobDataMap dataMap = context.MergedJobDataMap;
                string tag = dataMap.GetString("tag");
                string title = dataMap.GetString("title");
                string content = dataMap.GetString("content");
                string description = dataMap.GetString("description");
                string tels = dataMap.GetString("tels");

                //执行定时任务:模拟发送短信
                await Task.Run(() => Console.WriteLine($"发短信:【{tag}】,{title}:{content },{description},电话:{tels}。"));

                //await context.Scheduler.Shutdown();//表示完成当前的定时任务,关闭调度器

                //记入日志
                Console.WriteLine("执行了一次定时任务,记入日志");
            }
            catch (Exception ex)
            {
                //记入日志Log.Error()
                Console.WriteLine(ex.Message);
            }
    }

    //将创建定时任务的所有操作封装在此
    public static async void SendMessage(string starttime, string cronStr,string tag, string title, string content,string description, string tels)
    {
        try
        {
            //创建调度器
            IScheduler scheduler = await new StdSchedulerFactory().GetScheduler();
            //为任务准备参数
            DateTime time = DateTime.Parse(starttime);
            JobDataMap jobData = new JobDataMap()
            {
                new KeyValuePair<string, object>("tag", tag),
                new KeyValuePair<string, object>("title", title),
                new KeyValuePair<string, object>("content", content),
                new KeyValuePair<string, object>("description", description),
                new KeyValuePair<string, object>("tels", tels),
            };
            //创建任务:
            //注意可以用时间做组名:DateTime.Now.ToLongDateString()
            IJobDetail job = JobBuilder.Create<TestJob2>()
                                       .WithIdentity("Testjob1", "group1")
                                       .SetJobData(jobData)
                                       .Build();
            //创建触发器
            ITrigger trigger = TriggerBuilder.Create()
                                             .WithIdentity("triger1", "group1")
                                             .StartAt(time)//触发器开始时间//.StartNow()现在开始
                                             .WithCronSchedule(cronstr)
                                             .Build();
            //将任务和触发器添加到调度器中
            await scheduler.ScheduleJob(job, trigger);
            await scheduler.Start();
        }
        catch (Exception ex)
        {
            //记入日志
            Console.WriteLine(ex.Message);
        }
    }
}

调用:

public static async void PackageJob()
{
    //从系统当前时间,每隔5s,发送一条短信:【新闻】,新冠病毒,治愈者越来越多,普天同庆,10086。
    await Task.Run(() => TestJob2.SendMessage(DateTime.Now .ToString(),"/5 * * ? * *","新闻", "新冠病毒", "治愈者越来越多", "普天同庆", "10086"));
}

【代码说明】

  • 使用JobDataMap类型存放需要传递到IJob接口的Excute(IJobExecutionContext context)方法中

    JobDataMap中以键值对的方式存放数据,jobDataMao.Add("key",value)

  • 在定义Job的时候,使用触发器对象中的方法jobBuilder.SetJobData(jobData)将JobDataMap类型的数据传递到任务中

  • 使用JobDataMap dataMap = context.MergedJobDataMap;获取传递到Excute()中的JobDataMap类型的数据

    使用string value = dataMap.GetString("key");获取数据

  • 因为定时任务的是延时的执行的,所以切记一定要把每个周期中执行的定时任务记入到日志中,便于维护管理!

  • 注意,因为实现了IJob接口的任务类,其Excute()方法是在一个单独的线程中运行的,所以其异常的处理也在Excute()中使用try……catch……进行处理

  • BTW:在MVC项目中使用Quartz .NET,直接在Global.asax.cs中的Application_Start()运行封装好的定时任务即可

    注意:使用Quartz.NET中的Job,是无法实现任何关于Web的相关操作


2.5 关于调度器的一些说明

  • 一个调度器中可以调度多个方法

    使用 scheduler.ScheduleJob(job,trigger)将指定的任务和触发器添加到指定的调度器中,可以多次添加,从而实现一个调度器中调度多个任务

    但是有一点要注意:一个任务可以有多个触发器,但是一个触发器只能对应一个任务

  • 调度器可以添加任务,那么就一定是可以移除任务的

    //停止触发器
    await scheduler.PauseTrigger(triggerKey);
    //移除触发器
    await scheduler.UnscheduleJob(triggerKey);
    //删除任务
    await scheduler.DeleteJob(jobkey);
    
  • 调度器可以开始运行,那么就一定停止运行:

    context.Scheduler.Shutdown();表示完成当前的定时任务,关闭调度器

2.6 关于监听器

Undone……

可参考监听器:JobListeners/TriggerListeners/SchedulerListeners


参考及示例代码下载

免责声明:文章转载自《关于Quartz .NET(V3.0.7)的简要说明》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇WINDOWS7(vs2012+wdk7.6) 配置驱动开发环境Kubernetes2-K8s的集群部署下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ant Form 常用 api

经过 Form.create 包装的组件将会自带 this.props.form 属性,this.props.form 提供的 API 如下: 注意:使用 getFieldsValue getFieldValue setFieldsValue 等时,应确保对应的 field 已经用 getFieldDecorator 注册过了。 方法      说明...

Spring Boot集成mongodb

引自尚硅谷项目-尚医通 一、集成简介 spring-data-mongodb提供了MongoTemplate与MongoRepository两种方式访问mongodb,MongoRepository操作简单,MongoTemplate操作灵活,我们在项目中可以灵活适用这两种方式操作mongodb,MongoRepository的缺点是不够灵活,MongoT...

JAVA 上加密算法的实现用例,MessageDigest介绍

第 1 章基础知识 1.1. 单钥密码体制 单钥密码体制是一种传统的加密算法,是指信息的发送方和接收方共同使用同一把密钥进行加解密。 通常 , 使用的加密算法 比较简便高效 , 密钥简短,加解密速度快,破译极其困难。但是加密的安全性依靠密钥保管的安全性 , 在公开的计算机网络上安全地传送和保管密钥是一个严峻的问题,并且如果在多用户的情况下密钥的保管安全性也...

Solr与MySQL查询性能对比

测试环境 本文简单对比下Solr与MySQL的查询性能速度。 测试数据量:10407608     Num Docs: 10407608 普通查询 这里对MySQL的查询时间都包含了从MySQL Server获取数据的时间。 在项目中一个最常用的查询,查询某段时间内的数据,SQL查询获取数据,30s左右 SELECT * FROM `tf_hotspotd...

DevExpress WinForm MVVM数据和属性绑定指南(Part 1)

根据您绑定的属性,存在以下三种可能的情况: 常规绑定- ViewModel属性绑定到任何不可编辑的View元素属性。由于该元素不可编辑,因此您无需将更新通知发送回绑定属性(单向绑定)。 数据绑定- Model属性(数据字段)绑定到编辑器属性。如果用户可以更改编辑器值,则需要更新绑定属性(双向绑定)。 属性依赖- 来自同一个ViewModel的两个属性被绑...

C# + ArcEngine 常用方法(不定时更新)

1、Arcengine调用GP服务,抛出异常方法 object sev = null; try{ Application.DoEvents(); gp.Execut...