定时调度之Quartz

时间:2021-02-22 09:12:15

 工作中我们经常碰到定时或者固定时间点去做一些事情,然后每天到时间点就会去做这样的事情,如果理解这样的场景,我们就要引入今天我们的主角Quartz,其实这个跟数据库的作业类似,但是不仅仅局限于数据库。

一: quartZ引入&三大核心对象简介

1:在项目中打开Nuget管理,然后搜索QuartZ,现在最新的版本是3.0.7,需要在Framework4.5.2上面使用。

2:quartZ的三大核心对象

A:IScheduler:单元/实例,在这里去完成定时任务的配置,只有单元启动,里面的作业才能正常运行

B:IJob:任务,定时执行动作就是Job

C:ITrigger:定时策略(设置执行的频率或者执行方式)

 

二:三大核心对象的初始化以及使用如下:

定时调度之Quartz定时调度之Quartz
 1 #region scheduler
 2 Console.WriteLine("初始化scheduler......");
 3 StdSchedulerFactory factory = new StdSchedulerFactory();
 4 IScheduler scheduler = await factory.GetScheduler();
 5 //scheduler.ListenerManager.AddSchedulerListener(new CustomSchedulerListener());
 6 //scheduler.ListenerManager.AddTriggerListener(new CustomTriggerListener());
 7 //scheduler.ListenerManager.AddJobListener(new CustomJobListener());
 8 await scheduler.Start();
 9 #endregion
10 
11 //IJob  ITrigger
12 {
13     //创建作业
14     IJobDetail jobDetail = JobBuilder.Create<TestJob>()
15         .WithIdentity("testjob", "group1")
16         .WithDescription("This is TestJob")
17         .Build();
18 
19     //IJobDetail jobDetail = JobBuilder.Create<TestStatefulJob>()
20     //    .WithIdentity("testjob", "group1")
21     //    .WithDescription("This is TestJob")
22     //    .Build();
23 
24     jobDetail.JobDataMap.Add("student1", "Milor");
25     jobDetail.JobDataMap.Add("student2", "心如迷醉");
26     jobDetail.JobDataMap.Add("student3", "宇洋");
27     jobDetail.JobDataMap.Add("Year", DateTime.Now.Year);
28 
29     //ITrigger trigger = TriggerBuilder.Create()
30     //       .WithIdentity("trigger1", "group1")
31     //       .StartNow()
32     //       .WithSimpleSchedule(x => x
33     //           .WithIntervalInSeconds(10)
34     //           .WithRepeatCount(10)
35     //           .RepeatForever())
36     //           .WithDescription("This is testjob's Trigger")
37     //       .Build();
38 
39     //创建时间策略
40     ITrigger trigger = TriggerBuilder.Create()
41                   .WithIdentity("testtrigger1", "group1")
42                   .StartAt(new DateTimeOffset(DateTime.Now.AddSeconds(10)))
43                  //.StartNow()//StartAt
44                  .WithCronSchedule("5/10 * * * * ?")//每隔一分钟
45                                                     //"10,20,30,40,50,0 * * * * ?"
46                  .WithDescription("This is testjob's Trigger")
47                  .Build();
48 
49     trigger.JobDataMap.Add("student4", "Ray");
50     trigger.JobDataMap.Add("student5", "心欲无痕");
51     trigger.JobDataMap.Add("student6", "风在飘动");
52     trigger.JobDataMap.Add("Year", DateTime.Now.Year + 1);
53 
54     await scheduler.ScheduleJob(jobDetail, trigger);
55     Console.WriteLine("scheduler作业添加完成......");
56 }
View Code
定时调度之Quartz定时调度之Quartz
 1  public class TestJob : IJob
 2  {
 3      public TestJob()
 4         {
 5             Console.WriteLine("This is TestJob的构造。。。");
 6         }
 7      
 8      public async Task Execute(IJobExecutionContext context)
 9         {
10             await Task.Run(() =>
11             {
12                 Console.WriteLine();
13                 Console.WriteLine("*****************************");
14                 {
15                     JobDataMap dataMap = context.JobDetail.JobDataMap;
16                     Console.WriteLine(dataMap.Get("student1"));
17                     Console.WriteLine(dataMap.Get("student2"));
18                     Console.WriteLine(dataMap.Get("student3"));
19                     Console.WriteLine(dataMap.GetInt("Year"));
20                 }
21                 Console.WriteLine($"This is {Thread.CurrentThread.ManagedThreadId} {DateTime.Now}");
22                 //可以换成去数据库查询,可以做啥啥啥
23                 //但是很多情况下,我们也是需要参数的
24                 {
25                     JobDataMap dataMap = context.Trigger.JobDataMap;
26                     Console.WriteLine(dataMap.Get("student4"));
27                     Console.WriteLine(dataMap.Get("student5"));
28                     Console.WriteLine(dataMap.Get("student6"));
29                     Console.WriteLine(dataMap.GetInt("Year"));
30                 }
31                 {
32                     Console.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
33                     JobDataMap dataMap = context.MergedJobDataMap;
34                     Console.WriteLine(dataMap.Get("student1"));
35                     Console.WriteLine(dataMap.Get("student2"));
36                     Console.WriteLine(dataMap.Get("student3"));
37                     Console.WriteLine(dataMap.Get("student4"));
38                     Console.WriteLine(dataMap.Get("student5"));
39                     Console.WriteLine(dataMap.Get("student6"));
40                     Console.WriteLine(dataMap.GetInt("Year"));
41                 }
42                 Console.WriteLine("*****************************");
43                 Console.WriteLine();
44             });
45         }
46  }
View Code

 

三:任务或者定时策略传参

1:通过定时任务进行传参如下:

定时调度之Quartz

然后接收通过:

定时调度之Quartz

 2:定时策略进行传参

定时调度之Quartz

接收如下:

定时调度之Quartz

注意以上两种传参也可以统一通过下面的方式来接收参数,但是如果key相同,则会进行覆盖掉

定时调度之Quartz

四:常用的Trigggr

1:SimpleTrigger:从什么时间开始,间隔多久执行重复操作,可以限制最大次数,如下:

1  ITrigger trigger = TriggerBuilder.Create()
2         .WithIdentity("trigger1", "group1")
3         .StartNow()
4         .WithSimpleSchedule(x => x
5             .WithIntervalInSeconds(10)
6             .WithRepeatCount(10)
7             .RepeatForever()) //从什么时间开始,间隔多久执行重复操作,可以限制最大次数
8             .WithDescription("This is testjob's Trigger")
9         .Build();

2:Cron:表达式的方式,可以灵活订制时间规则(具体详情咨询

1 ITrigger trigger = TriggerBuilder.Create()
2               .WithIdentity("testtrigger1", "group1")
3               .StartAt(new DateTimeOffset(DateTime.Now.AddSeconds(10)))
4              //.StartNow()//StartAt
5              .WithCronSchedule("5/10 * * * * ?")//每隔一分钟 //"10,20,30,40,50,0 * * * * ?"
6              .WithDescription("This is testjob's Trigger")
7              .Build();

 

五:Listener框架的各个环节--事件能做的监听

如果我们自己写定时任务的时候,因为是定时或者周期去做一些事情,所以有时候有问题或者出现了什么故障,我们只能通过我们自己写一下具体的日志,但是Quartz里面的Listener里面内置封装了一些监听接口,分别为:ISchedulerListener,ITriggerListener,IJobListener,里面有一些方法可以让我们去做一下其它的事情,我们下面分别实现了三个接口,代码如下:

1:jobListerer

定时调度之Quartz定时调度之Quartz
 1 public class CustomJobListener : IJobListener
 2     {
 3         public string Name => "CustomJobListener";
 4 
 5         public async Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
 6         {
 7             await Task.Run(()=> {
 8                 Console.WriteLine($"CustomJobListener JobExecutionVetoed {context.JobDetail.Description}");
 9             });
10         }
11 
12         public async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
13         {
14             await Task.Run(() => {
15                 Console.WriteLine($"CustomJobListener JobToBeExecuted {context.JobDetail.Description}");
16             });
17         }
18 
19         public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default(CancellationToken))
20         {
21             await Task.Run(() => {
22                 Console.WriteLine($"CustomJobListener JobWasExecuted {context.JobDetail.Description}");
23             });
24         }
25     }
View Code

2:ITriggerListener

定时调度之Quartz定时调度之Quartz
 1 public class CustomTriggerListener : ITriggerListener
 2     {
 3         public string Name => "CustomTriggerListener";
 4 
 5         public async Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default(CancellationToken))
 6         {
 7             await Task.Run(() =>
 8             {
 9                 Console.WriteLine($"CustomTriggerListener TriggerComplete {trigger.Description}");
10             });
11         }
12 
13         public async Task TriggerFired(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
14         {
15             await Task.Run(() =>
16             {
17                 Console.WriteLine($"CustomTriggerListener TriggerFired {trigger.Description}");
18             });
19         }
20 
21         public async Task TriggerMisfired(ITrigger trigger, CancellationToken cancellationToken = default(CancellationToken))
22         {
23             await Task.Run(() =>
24             {
25                 Console.WriteLine($"CustomTriggerListener TriggerMisfired {trigger.Description}");
26             });
27         }
28 
29         /// <summary>
30         /// 要不要放弃job
31         /// </summary>
32         /// <param name="trigger"></param>
33         /// <param name="context"></param>
34         /// <param name="cancellationToken"></param>
35         /// <returns></returns>
36         public async Task<bool> VetoJobExecution(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
37         {
38             await Task.Run(() =>
39             {
40                 Console.WriteLine($"CustomTriggerListener TriggerMisfired {trigger.Description}");
41             });
42             return false;//false才能继续执行
43         }
44     }
View Code

3:ISchedulerListener

定时调度之Quartz定时调度之Quartz
  1 public class CustomSchedulerListener : ISchedulerListener
  2     {
  3         public async Task JobAdded(IJobDetail jobDetail, CancellationToken cancellationToken = default(CancellationToken))
  4         {
  5             await Task.Run(() =>
  6             {
  7                 Console.WriteLine($"This is {nameof(CustomSchedulerListener)} JobAdded {jobDetail.Description}");
  8             });
  9         }
 10 
 11         public Task JobDeleted(JobKey jobKey, CancellationToken cancellationToken = default(CancellationToken))
 12         {
 13             throw new NotImplementedException();
 14         }
 15 
 16         public Task JobInterrupted(JobKey jobKey, CancellationToken cancellationToken = default(CancellationToken))
 17         {
 18             throw new NotImplementedException();
 19         }
 20 
 21         public Task JobPaused(JobKey jobKey, CancellationToken cancellationToken = default(CancellationToken))
 22         {
 23             throw new NotImplementedException();
 24         }
 25 
 26         public Task JobResumed(JobKey jobKey, CancellationToken cancellationToken = default(CancellationToken))
 27         {
 28             throw new NotImplementedException();
 29         }
 30 
 31         public Task JobScheduled(ITrigger trigger, CancellationToken cancellationToken = default(CancellationToken))
 32         {
 33             throw new NotImplementedException();
 34         }
 35 
 36         public Task JobsPaused(string jobGroup, CancellationToken cancellationToken = default(CancellationToken))
 37         {
 38             throw new NotImplementedException();
 39         }
 40 
 41         public Task JobsResumed(string jobGroup, CancellationToken cancellationToken = default(CancellationToken))
 42         {
 43             throw new NotImplementedException();
 44         }
 45 
 46         public Task JobUnscheduled(TriggerKey triggerKey, CancellationToken cancellationToken = default(CancellationToken))
 47         {
 48             throw new NotImplementedException();
 49         }
 50 
 51         public Task SchedulerError(string msg, SchedulerException cause, CancellationToken cancellationToken = default(CancellationToken))
 52         {
 53             throw new NotImplementedException();
 54         }
 55 
 56         public Task SchedulerInStandbyMode(CancellationToken cancellationToken = default(CancellationToken))
 57         {
 58             throw new NotImplementedException();
 59         }
 60 
 61         public Task SchedulerShutdown(CancellationToken cancellationToken = default(CancellationToken))
 62         {
 63             throw new NotImplementedException();
 64         }
 65 
 66         public Task SchedulerShuttingdown(CancellationToken cancellationToken = default(CancellationToken))
 67         {
 68             throw new NotImplementedException();
 69         }
 70 
 71         public async Task SchedulerStarted(CancellationToken cancellationToken = default(CancellationToken))
 72         {
 73             await Task.Run(() =>
 74             {
 75                 Console.WriteLine($"This is {nameof(CustomSchedulerListener)} SchedulerStarted ");
 76             });
 77         }
 78 
 79         public async Task SchedulerStarting(CancellationToken cancellationToken = default(CancellationToken))
 80         {
 81             await Task.Run(() =>
 82             {
 83                 Console.WriteLine($"This is {nameof(CustomSchedulerListener)} SchedulerStarting ");
 84             });
 85         }
 86 
 87         public Task SchedulingDataCleared(CancellationToken cancellationToken = default(CancellationToken))
 88         {
 89             throw new NotImplementedException();
 90         }
 91 
 92         public Task TriggerFinalized(ITrigger trigger, CancellationToken cancellationToken = default(CancellationToken))
 93         {
 94             throw new NotImplementedException();
 95         }
 96 
 97         public Task TriggerPaused(TriggerKey triggerKey, CancellationToken cancellationToken = default(CancellationToken))
 98         {
 99             throw new NotImplementedException();
100         }
101 
102         public Task TriggerResumed(TriggerKey triggerKey, CancellationToken cancellationToken = default(CancellationToken))
103         {
104             throw new NotImplementedException();
105         }
106 
107         public Task TriggersPaused(string triggerGroup, CancellationToken cancellationToken = default(CancellationToken))
108         {
109             throw new NotImplementedException();
110         }
111 
112         public Task TriggersResumed(string triggerGroup, CancellationToken cancellationToken = default(CancellationToken))
113         {
114             throw new NotImplementedException();
115         }
116     }
View Code

然后通过下面代码来融合到实例中:

1  StdSchedulerFactory factory = new StdSchedulerFactory();
2             IScheduler scheduler = await factory.GetScheduler();
3             scheduler.ListenerManager.AddSchedulerListener(new CustomSchedulerListener());
4             scheduler.ListenerManager.AddTriggerListener(new CustomTriggerListener());
5             scheduler.ListenerManager.AddJobListener(new CustomJobListener());
6             await scheduler.Start();

这样就完美的结合在一起了,然后实例,任务,策略每次发生的动作,都会以日志的形式输出来,当然可以记录任何形式的日志。

 

六:LogProvider可以展示框架运行的一些信息

Quartz.Logging内置了一些记录日志的类,然后需要记录日志的话,可以直接拿来使用,不用自己再去引用配置等记录日志了,下面是自己试着写了一个:

定时调度之Quartz定时调度之Quartz
 1 public class CustomConsoleLogProvider : ILogProvider
 2     {
 3         public Logger GetLogger(string name)
 4         {
 5             return new Logger((level, func, exception, parameters) =>
 6             {
 7                 if (level >= LogLevel.Info && func != null)
 8                 {
 9                     Console.WriteLine($"[{ DateTime.Now.ToLongTimeString()}] [{ level}] { func()} {string.Join(";", parameters.Select(p => p == null ? " " : p.ToString()))}  自定义日志{name}");
10                 }
11                 return true;
12             });
13         }
14         public IDisposable OpenNestedContext(string message)
15         {
16             throw new NotImplementedException();
17         }
18 
19         public IDisposable OpenMappedContext(string key, string value)
20         {
21             throw new NotImplementedException();
22         }
23     }
View Code

然后在DispatcherManager中的init方法中

定时调度之Quartz

 

 这样即实现了log的日志

如果想要测试,可以通过:

定时调度之Quartz定时调度之Quartz
 1  static void Main(string[] args)
 2  {
 3      try
 4      {
 5          Console.WriteLine("QuartZ.Net定时调度");
 6          DispatcherManager.Init().GetAwaiter().GetResult();
 7      }
 8      catch (Exception ex)
 9      {
10          Console.WriteLine(ex.Message);
11      }
12      Console.Read();
13  }
View Code