最近工作中遇到了Quartz.net,为了更好的理解公司代码的写法,于是就好好的研究了一下这个东西,确实是好东西,既然是好东西,我就拿出来分享一下。万丈高楼平地起,我们也是从入门开始吧。
欢迎使用Quartz.NET快速入门指南。 在阅读本指南时,希望看到以下详细信息:
1、下载Quartz.NET
2、安装Quartz.NET
3、根据您自己的特定需求配置Quartz
4、开始示例应用程序
一、下载并安装
您可以直接下载zip文件或使用NuGet包来获取文件。但是二者是有区别的,NuGet包只包含运行Quartz.NET所需的二进制文件,Zip文件就不一样了,包含源代码、示例和Quartz.NET服务器示例应用程序。
Zip文件
简短版本:如果你成功下载了Quartz.NET压缩包文件,只要将ZIP文件解压,从bin目录中获取Quartz.dll文件,就可以开始使用它了。
Quartz核心库是一个非常干净和独立的类库,不会强行依赖于任何的其他二进制文件。 如果您想使用JSON.NET的进行JSON序列化时,您可以根据需要选择加入更多依赖项。同时您只要保证在应用程序中包含了Quartz.dll文件就可以成功运行Quartz.NET,也会和其他的二进制文件相处融洽。 因此,只需将Quartz.dll文件添加到使用它们的Visual Studio项目中就可以安全运行。 您可以从路径bin \ your-target-framework-version \ release \ Quartz中提取的存档中找到这些dll。
二、NuGet包
没有比这种方法更简单的做法了,只需启动Visual Studio(安装了NuGet)并从包管理器扩展中添加对Quartz包的引用:
1、右键单击项目的“引用”(References),然后选择“管理 NuGet 程序包(N)”(Manage NuGet Packages(N)) ...
2、从左侧选择“浏览or在线”类别
3、在左上方的搜索中输入Quartz,然后按Enter键
4、从搜索结果中选择Quartz.NET并点击安装
5、完成!
或者使用NuGet的命令行来安装:
Install-Package Quartz
如果要添加JSON序列化,只需以相同的方式添加Quartz.Serialization.Json包。
三、配置
这是大有点! Quartz.NET是一个支持高度可配置的库。Quartz.NET提供三种的配置信息的方式(不相互排斥):
1、以编程方式通过向调度程序工厂提供NameValueCollection参数
2、通过使用quartz-element的标准youapp.exe.config配置文件(仅限完整的.NET框架)
3、应用程序根目录中的quartz.config文件(适用于.NET Core和完整的.NET Framework)
您可以在Quartz.NET zip文件中找到所有这些替代品的样本。
Quartz Configuration Reference中提供了可用属性的完整文档。
为了快速启动和运行,提供了基本的quartz.config的配置文件看起来应该像这样:
quartz.scheduler.instanceName = MyScheduler
quartz.jobStore.type = Quartz.Simpl.RAMJobStore,Quartz
quartz.threadPool.threadCount = 3
请记住在Visual Studio的文件属性页上设置“复制到输出目录”以使值始终为“复制”。否则,如果配置不在构建目录中,则不会看到该配置。
此配置创建的调度程序具有以下特征:
quartz.scheduler.instanceName - 此调度程序的名称将为“MyScheduler”。
quartz.threadPool.threadCount - 最多可同时运行3个作业。
quartz.jobStore.type - 所有Quartz的数据,例如作业和触发器的详细信息,都保存在内存中(而不是数据库中)。即使你有一个数据库并希望在Quartz中使用它,我建议你在使用数据库打开一个全新的维度之前让Quartz使用RamJobStore。
实际上,如果你不想定义这些属性,Quartz.NET会提供合理的默认值
四、先来一个简单的实例程序
现在您已经下载并安装了Quartz,现在是时候启动并运行一个示例应用程序了。 以下代码获取调度程序的实例,启动它,然后将其关闭:
复制代码
1 using System;
2 using System.Threading.Tasks;
3
4 using Quartz;
5 using Quartz.Impl;
6
7 namespace QuartzSampleApp
8 {
9 public class Program
10 {
11 private static void Main(string[] args)
12 {
13 // trigger async evaluation
14 RunProgram().GetAwaiter().GetResult();
15 }
16
17 private static async Task RunProgram()
18 {
19 try
20 {
21 // 从Factory获取Scheduler实例
22 NameValueCollection props = new NameValueCollection
23 {
24 { "quartz.serializer.type", "binary" }
25 };
26 StdSchedulerFactory factory = new StdSchedulerFactory(props);
27 IScheduler scheduler = await factory.GetScheduler();
28
29 // 并启动它
30 await scheduler.Start();
31
32 // some sleep to show what's happening
33 await Task.Delay(TimeSpan.FromSeconds(10));
34
35 // 当您准备关闭程序时,最后关闭调度程序
36 await scheduler.Shutdown();
37 }
38 catch (SchedulerException se)
39 {
40 await Console.Error.WriteLineAsync(se.ToString());
41 }
42 }
43 }
44 }
复制代码
从Quartz 3.0开始,当在scheduler.Shutdown() 之后没有剩下的代码要执行时,你的应用程序将终止,因为没有任何活动的线程。 如果希望在处理Task.Delay和Shutdown之后调度程序继续运行,则应手动阻止退出应用程序。
现在运行该程序将不会显示任何内容。 10秒后,程序将终止。 让我们添加一些日志记录到控制台。
五、增加日志功能
LibLog可以配置为使用不同的日志框架; 即Log4Net,NLog和Serilog。
当LibLog没有检测到任何其他日志框架存在时,它将是不做任何事的。 如果您还没有一个设置好的日志框架,我们可以配置一个自定义的日志记录器提供程序,只需登录到控制台即可显示输出。
复制代码
1 LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());
2
3 private class ConsoleLogProvider : ILogProvider
4 {
5 public Logger GetLogger(string name)
6 {
7 return (level, func, exception, parameters) =>
8 {
9 if (level >= LogLevel.Info && func != null)
10 {
11 Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);
12 }
13 return true;
14 };
15 }
16
17 public IDisposable OpenNestedContext(string message)
18 {
19 throw new NotImplementedException();
20 }
21
22 public IDisposable OpenMappedContext(string key, string value)
23 {
24 throw new NotImplementedException();
25 }
26 }
复制代码
六、探索使用 Job 作业的完整过程
现在,当我们启动应用程序时,我们应该获得更多信息。
复制代码
[10:52:50] [Info] Using object serializer: Quartz.Simpl.BinaryObjectSerializer, Quartz
[10:52:50] [Info] Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl
[10:52:50] [Info] Quartz Scheduler v.3.0.7.0 created.
[10:52:50] [Info] RAMJobStore initialized.
[10:52:50] [Info] Scheduler meta-data: Quartz Scheduler (v3.0.7.0) 'QuartzScheduler' with instanceId 'NON_CLUSTERED'
Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'Quartz.Simpl.DefaultThreadPool' - with 10 threads.
Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistence. and is not clustered.
[10:52:50] [Info] Quartz scheduler 'QuartzScheduler' initialized
[10:52:50] [Info] Quartz scheduler version: 3.0.7.0
[10:52:50] [Info] Scheduler QuartzScheduler_$_NON_CLUSTERED started.
复制代码
我们需要一个简单的测试工作来测试功能,让我们创建HelloJob来向控制台输出问候语。
复制代码
1 public sealed class HelloJob : IJob
2 {
3 public async Task Execute(IJobExecutionContext context)
4 {
5 await Console.Out.WriteLineAsync("Greetings from HelloJob!");
6 }
7 }
复制代码
要做一些有趣的事情,您需要在Task.Delay之前的Start() 方法之后使用代码。
复制代码
1 // 定义job作业并将其绑定到HelloJob类
2 IJobDetail job = JobBuilder.Create<HelloJob>()
3 .WithIdentity("job1", "group1")
4 .Build();
5
6 //触发作业立即运行,然后每10秒重复一次
7 ITrigger trigger = TriggerBuilder.Create()
8 .WithIdentity("trigger1", "group1")
9 .StartNow()
10 .WithSimpleSchedule(x => x
11 .WithIntervalInSeconds(10)
12 .RepeatForever())
13 .Build();
14
15 //告诉 quartz 使用我们的触发器安排作业
16 await scheduler.ScheduleJob(job, trigger);
复制代码
完整的控制台应用程序现在看起来像这样
复制代码
1 using System;
2 using System.Threading.Tasks;
3
4 using Quartz;
5 using Quartz.Impl;
6 using Quartz.Logging;
7
8 namespace QuartzSampleApp
9 {
10 public class Program
11 {
12 private static void Main(string[] args)
13 {
14 LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());
15
16 RunProgram(www.gcyl159.com).GetAwaiter().GetResult();
17
18 Console.WriteLine("Press any key to close the application");
19 Console.ReadKey(www.gcyl152.com/ );
20 }
21
22 private static async Task RunProgram()
23 {
24 try
25 {
26 // Grab the Scheduler instance from the Factory
27 NameValueCollection props =www.michenggw.com new NameValueCollection
28 {
29 { "quartz.serializer.type", "binary" }
30 };
31 StdSchedulerFactory factory = new StdSchedulerFactory(props);
32 IScheduler scheduler = await factory.GetScheduler();
33
34 // and start it off
35 await scheduler.Start();
36
37 // define the job and tie it to our HelloJob class
38 IJobDetail job = JobBuilder.Create<HelloJob>(www.yigouyule2.cn)
39 .WithIdentity("job1", "group1")
40 .Build();
41
42 // Trigger the job to run now, and then repeat every 10 seconds
43 ITrigger trigger = TriggerBuilder.Create()
44 .WithIdentity("trigger1", "group1")
45 .StartNow()
46 .WithSimpleSchedule(x => x
47 .WithIntervalInSeconds(10)
48 .RepeatForever(www.leyouzaixian2.com))
49 .Build(www.365soke.com);
50
51 // Tell quartz to schedule the job using our trigger
52 await scheduler.ScheduleJob(job, trigger);
53
54 // some sleep to show what's happening
55 await Task.Delay(TimeSpan.FromSeconds(60));
56
57 // and last shut down the scheduler when you are ready to close your program
58 await scheduler.Shutdown();
59 }
60 catch (SchedulerException se)
61 {
62 Console.WriteLine(se);
63 }
64 }
65
66 // simple log provider to get something to the console
67 private class ConsoleLogProvider : ILogProvider
68 {
69 public Logger GetLogger(string name)
70 {
71 return (level, func, exception, parameters) =>
72 {
73 if (level >= LogLevel.Info && func != null)
74 {
75 Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);
76 }
77 return true;
78 };
79 }
80
81 public IDisposable OpenNestedContext(string message)
82 {
83 throw new NotImplementedException();
84 }
85
86 public IDisposable OpenMappedContext(string key, string value)
87 {
88 throw new NotImplementedException();
89 }
90 }
91 }
92
93 public class HelloJob : IJob
94 {
95 public async Task Execute(IJobExecutionContext context)
96 {
97 await Console.Out.WriteLineAsync("Greetings from HelloJob!");
98 }
99 }
100 }
复制代码