【翻译 博主注释版】Quartz.NET - Quartz.NET快速入门
一. Quartz.NET快速入门
欢迎翻阅 Quartz.NET 快速入门。您将从此入门中获得如下详细内容:
- 下载 Quartz.NET
- 安装 Quartz.NET
- 根据你需要的规则配置 Quartz
- 启动示例程序
二. 安装及下载
你既可以下载 zip 文件,也可以使用 NuGet 包。Nuget 包只包含了运行 Quartz.NET 所需要的二进制文件(编译后的dll文件),而 zip 文件中包含了源码、Quartz.NET的服务器的示例代码。
1. 可以在网上搜索 Quartz.NET:
- 官网地址:https://www.quartz-scheduler.net/
2.然后点击 Download 即可下载:
- GitHub下载页面:https://github.com/quartznet/quartznet/releases
- 最新版 3.0.7
- 一个是 zip 的 windows 版本
- 一个是 tar.gz 的 Linux 版本
3. 下载之后,zip中的内容:
Zip归档
操作简述:下载了 Quartz.NET 之后,将其解压到某个地方,然后从 bin 目录中的获取 Quartz.dll 并使用它。
Quartz.NET 的核心类库不包含任何硬编码的依赖项。当你选择使用需要 JSON.NET 的 JSON 序列化包的时候,你可以加入更多依赖项。如要想要成功的运行 Quartz.NET,你至少在运用程序目录下放有 Quartz.dll。所以只需要将 Quartz.NET 作为一个引用添加到 Visual Studio 中并使用它们。你可以从 " bin\your-target-framework-version\release\Quartz " 路径的目录下的提取文件中找到这些 dll。
获取源码:
1. 通过下载 zip 通过编译的方式
Tips:
【1】 如果再打开的过程中出现:
" error : 项目的默认 XML 命名空间必须为 MSBuild XML 命名空间。如果项目是用 MSBuild 2003 格式创建的,请将 xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 添加到 <Project> 元素中。如果项目是用旧的 1.0 或 1.2 格式创建的,请将其转换为 MSBuild 2003 格式。"
这是说明 VS 需要 2017的版本才能打开,建议升级到 2017版本。
【2】 在修改为 VS2017打开之后,如果出现以下问题:
那么要在 VS 的 " 工具 " -> " 选项... " 所打开的选项窗体中,选择 " Nuget 包管理器 " -> " 常规 " 选项中勾选 " 程序包还原 " 中的所有的选项:
【3】在修复了【1】【2】问题之后,我们编译还是会有如下问题:
此问题暂时还没有解决,这个博主在 GitHub 中已经问过 Quartz.NET 的作者了:
2. 通过 Git 下载,然后再进行编译的方法
【1】安装 Git,然后找一个文件夹,右键选择 " Git Bash Here "
【2】打开的窗体中,输入 " git clone git@github.com:quartznet/quartznet.git ",然后等待下载完成之后再输入 " .\build.cmd " 来执行下载的 Quartz.NET的代码下 build.cmd 批处理文件
git clone git@github.com:quartznet/quartznet.git
.\build.cmd
【3】执行成功下载完成之后(图1),运行 build.cmd (图2),接着进入 VS 2017 就可以成功编译生成(图3)
图1
图2
图3
三. NuGet包
最简单的获取方式。只需要启动安装用 Nuget 的 Visual Studio,并且从 " Nuget 包管理器 " 中添加对 Quartz 的引用。
- 右键单击项目引用,并从右键菜单中选择 " 管理 Nuget 程序包 " ...
- 从左侧选择在线类别
- 在右上方的搜索框中写入 " Quartz ",然后点击回车
- 从搜索的结果中选择 " Quartz.NET ",然后点击安装
- 完成!
或者,通过 NuGet 命令行:
Install-Package Quartz
如果你想要添加 JSON 序列化的内容,只需要用同样的方法添加 Quartz.Serialization.Json。
四. 配置
这才是重点!Quarty.NET 是一个配置能力很强的类库。这里有三种方式(它们并不相互排斥)来提供 Quartz.NET 的配置信息:
- 以编程的方式向调度工厂提供 NameValueCollection 的参数
- 使用 quartz-element 通过标准的 youapp.exe.config 配置文件(适用于完整版的 .NET Framework)
- 通过使用在你应用程序根目录下的 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 文件属性页中,设置 " Copy to Output Directory " 的值为 " Copy always "。否则,如果配置不在构建目录中创建,那么将不能看到它。
通过上面的配置创建的调度具有如下的特点:
- quartz.scheduler.instance - 这个调度器的名称将会是 " MyScheduler "。
- quartz.threadPool.threadCount - 最多可以同时运行3个工作。
- quartz.jobStore.type - 所有 Quartz 的数据,比如作业和触发器的详细信息,都保存在内存中(而不是在数据库中)。如果你有一个数据并且希望配合 Quartz 一起使用它,我建议你在使用数据库打开一个全新的维度之前,先让 Quartz 与 RamJobStore 一起工作。
实际上你不需要定义这些你不想要的属性,Quartz.NET将使用合适的默认值。
五. 开始一个示例程序
现在,你应该已经下载并且安装了 Quartz,是时候穿件一个示例程序来运行了。下面的程序时一个调度程序的例子,我们启动它,然后再关闭它:
Program.cs
using System; using System.Threading.Tasks; using Quartz; using Quartz.Impl; namespace QuartzSampleApp { public class Program { private static void Main(string[] args) { // trigger async evaluation RunProgram().GetAwaiter().GetResult(); } private static async Task RunProgram() { try { // Grab the Scheduler instance from the Factory NameValueCollection props = new NameValueCollection { { "quartz.serializer.type", "binary" } }; StdSchedulerFactory factory = new StdSchedulerFactory(props); IScheduler scheduler = await factory.GetScheduler(); // and start it off await scheduler.Start(); // some sleep to show what's happening await Task.Delay(TimeSpan.FromSeconds(60)); // and last shut down the scheduler when you are ready to close your program await scheduler.Shutdown(); } catch (SchedulerException se) { await Console.Error.WriteLineAsync(se.ToString()); } } } }
自从 Quartz 3.0 之后,当执行了 scheduler.Shutdown() 之后没有任何可执行代码的时候,应用程序终止,这是因为将不再会有任何活动的线程。如果希望调度程序在 Task.Delay 和 Shutdown 被执行之后,也能继续执行,则应该手动阻塞应用程序退出。
当前,运行上面的程序将不会显示任何信息。当10秒过去了之后,程序将会终止。让我们向程序控制台添加一些日志输出。
六. 增加日志
LibLog 可以配置为使用不同的日志框架,如 Log4Net、Nlog 和 Serilong。
LogProvider.SetCurrentLogProvider(new ConsoleLogProvider()); private class ConsoleLogProvider : ILogProvider { public Logger GetLogger(string name) { return (level, func, exception, parameters) => { if (level >= LogLevel.Info && func != null) { Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters); } return true; }; } public IDisposable OpenNestedContext(string message) { throw new NotImplementedException(); } public IDisposable OpenMappedContext(string key, string value) { throw new NotImplementedException(); } }
七. 尝试应用程序并添加作业
现在,在我们运行程序之后,应该得到了更多信息。
[12.51.10] [Info] Quartz.NET properties loaded from configuration file 'C:\QuartzSampleApp\quartz.config'
[12.51.10] [Info] Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl
[12.51.10] [Info] Quartz Scheduler v.0.0.0.0 created.
[12.51.10] [Info] RAMJobStore initialized.
[12.51.10] [Info] Scheduler meta-data: Quartz Scheduler (v0.0.0.0) 'MyScheduler' 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 3 threads.
Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistence. and is not clustered.
[12.51.10] [Info] Quartz scheduler 'MyScheduler' initialized
[12.51.10] [Info] Quartz scheduler version: 0.0.0.0
[12.51.10] [Info] Scheduler MyScheduler_$_NON_CLUSTERED started.
我们需要一个简单的测试作业来测试功能,让我们创建一个输出 " Greetings from HelloJob! " 到控制台的类 HelloJob。
public class HelloJob : IJob { public async Task Execute(IJobExecutionContext context) { await Console.Out.WriteLineAsync("Greetings from HelloJob!"); } }
接着我们做一些有趣的事情,你需要在 Task.Delay 之前,在 Start() 之后,编写下面的代码:
// define the job and tie it to our HelloJob class IJobDetail job = JobBuilder.Create<HelloJob>() .WithIdentity("job1", "group1") .Build(); // Trigger the job to run now, and then repeat every 10 seconds ITrigger trigger = TriggerBuilder.Create() .WithIdentity("trigger1", "group1") .StartNow() .WithSimpleSchedule(x => x .WithIntervalInSeconds(10) .RepeatForever()) .Build(); // Tell quartz to schedule the job using our trigger await scheduler.ScheduleJob(job, trigger);
现在,完整的控制台程序看上去应该是这样:
using System; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Logging; namespace QuartzSampleApp { public class Program { private static void Main(string[] args) { LogProvider.SetCurrentLogProvider(new ConsoleLogProvider()); RunProgramRunExample().GetAwaiter().GetResult(); Console.WriteLine("Press any key to close the application"); Console.ReadKey(); } private static async Task RunProgramRunExample() { try { // Grab the Scheduler instance from the Factory NameValueCollection props = new NameValueCollection { { "quartz.serializer.type", "binary" } }; StdSchedulerFactory factory = new StdSchedulerFactory(props); IScheduler scheduler = await factory.GetScheduler(); // and start it off await scheduler.Start(); // define the job and tie it to our HelloJob class IJobDetail job = JobBuilder.Create<HelloJob>() .WithIdentity("job1", "group1") .Build(); // Trigger the job to run now, and then repeat every 10 seconds ITrigger trigger = TriggerBuilder.Create() .WithIdentity("trigger1", "group1") .StartNow() .WithSimpleSchedule(x => x .WithIntervalInSeconds(10) .RepeatForever()) .Build(); // Tell quartz to schedule the job using our trigger await scheduler.ScheduleJob(job, trigger); // some sleep to show what's happening await Task.Delay(TimeSpan.FromSeconds(60)); // and last shut down the scheduler when you are ready to close your program await scheduler.Shutdown(); } catch (SchedulerException se) { Console.WriteLine(se); } } // simple log provider to get something to the console private class ConsoleLogProvider : ILogProvider { public Logger GetLogger(string name) { return (level, func, exception, parameters) => { if (level >= LogLevel.Info && func != null) { Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters); } return true; }; } public IDisposable OpenNestedContext(string message) { throw new NotImplementedException(); } public IDisposable OpenMappedContext(string key, string value) { throw new NotImplementedException(); } } } public class HelloJob : IJob { public async Task Execute(IJobExecutionContext context) { await Console.Out.WriteLineAsync("Greetings from HelloJob!"); } } }
现在去探索一下 Quartz.NET 吧!你可以继续阅读教程。