.NET 定时执行工具 - Quartz(官方翻译)

时间:2022-11-30 07:57:44

官方网站 : https://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/index.html

Quartz.NET 快速向导
欢迎来到 Quartz.NET 快速向导, 当你读到这篇向导, 你可能希望看到以下内容:
1. 下载 Quartz.NET
2. 安装 Quartz.NET
3. 根据您自身的特殊情况配置 Quartz.NET
4. 开始编写简单的应用

下载和安装
你可以选择下载 Zip文件或者是 NuGet包. Nuget 包仅仅包含了 Quartz.NET 运行所需要的二进制文件. Zip文件中包含了源代码, 简单的实例和基于Quartz.NET 简单的应用.

Zip 文档
短版本: 下载 Quartz.NET 并且解压在任意目录下. 首先关注 bin 目录下的 Quartz.dll 文件, 并且可以开始尝试使用它
Quartz Core 的核心库没有任何其他的依赖关系. 你可以选择其他更多的依赖项. 比如选择 JSON.NET 为您来提供 JSON 序列化的服务
但是, 想要成功运行 Quartz 服务的话 Quartz.dll 是必不可少的.
所以, 只用吧相关的 dll 引入进你的 Visual Studio IDE 中就可以使用他们了.
你可以从以下目录中找到相关的 dll 文件 bin\your-target-framework-version\release\Quartz.


NuGet 安装
只用从 Visual Studio 中使用包管理器来安装和引用 Quartz
右击您的项目引用, 选择 Manage Nuget Packages
然后在左边区域选择在线查找
输入 Quartz 并且点击确定
从搜到的结果里 选择 Quartz.NET 点击安装
完成

或者你也可以使用 NuGet 命令来进行安装
Install-Package Quartz
如果你希望加入 JSON 序列化的功能, 只用按照相同的套路来安装 Quartz.Serialization.Json 包即可

配置
这是一个重点, Quartz.NET 是一个高可配置的库. 这里有三种方式(不是互斥的)
来对 Quartz.NET 进行配置
1. 在程序中通过 NameValueCollection 参数来进行配置 scheduler 工厂
2. 通过标准的 应用程序配置文件来进行配置 (只能在 .NET Framework 下进行)
3. 通过在应用程序中的根目录下的 quartz.config 配置文件进行配置(在 .NET Core 下和 .NET Framework 下都可以工作)

你可以在 Quartz.NET 的 Zip 文件目录下找到简单的模板

所有可用的属性介绍都可以在 https://www.quartz-scheduler.net/documentation/quartz-3.x/configuration/index.html 中找到


为了能快速启动和运行, 一个基本的配置类似于这样的

quartz.scheduler.instanceName = MyScheduler
quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz
quartz.threadPool.threadCount = 3

 

请记住, 在 Visual Studio 中请设置这个文件属性为<始终复制>
不然这个文件就会在项目编译的时候被忽略掉

由这个配置创建的调度器有以下特性
quartz.scheduler.instanceName - 这是用来配置调度器的名字
quartz.threadPool.threadCount - 最大数量的并行作业数量
quartz.jobStore.type - 所有的 Quartz 的数据, 比如作业的触发和细节. 都会被保存在内存中(而不是数据库中). 即使你希望将 Quartz 放在数据库中运行. |我建议你得到石英与RAMOPPORD商店工作之前,你打开一个全新的维度与数据库一起工作。|


事实上, 你如果不进行这些属性的配置的话, 那么 Quartz 也会使用缺省值进行默认定义

开始尝试一个简单的应用
现在, 你已经下载并且安装了 Quartz, 时候开始运行一个简单的程序了.
跟着下面的代码, 获得一个调度器的实例, 然后启动, 最后关闭

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());
            }
        }
    }
}

 

当你从 StdSchedulerFactory.GetDefaultScheduler() 获得一个调度器的时候.
在一般情况下你的应用程序就不会终止了, 直到你关闭了调度器. 因为在开启的状态下始终有一个活动线程在运行.

不运行程序的话就不会显示任何东西, 直到10秒钟之后, 程序会自动终止.
接下来让我们输出一些日志到控制台

添加日志
LibLog 可以通过配置在底层使用不同的日志框架. 比如 Log4Net,NLog和Serilog.

当LibLog找不到任何正在使用的日志框架的时候, 他就不能输出了, 当我们没有可用的日志的框架的时候, 我们可以通过自定义配置一个日志提供器来让日志仅仅显示在控制台.


尝试运行应用并且添加任务
现在我们需要在程序运行的时候获得更多详细的信息
我们需要创建一个简单的测试方法, 添加一个 HelloJob, 并且在控制台显示 Greetings

public class HelloJob : IJob
{
    public Task Execute(IJobExecutionContext context)
    {
        await Console.Out.WriteLineAsync("Greetings from HelloJob!");
    }
}

 

开始做一些有趣的事情, 你需要在 Start() 方法后面, TaskDelay 方法的前面编写这样的代码

// 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!");
        }
    }
}

 

现在, 有更多有趣的东西 你可以阅读接下来的教程....

 

 

教程1
在你使用 调度器 之前, 你需要实例化
你可以使用 ISchedulerFactory 实现器进行实现

调度器被实例化一次之后, 它就可以开始, 闲置和关闭了.
注意, 调度器一旦被关闭, 在重新实例化之前就不可以重新开始启动了.
直到调度器开始运行, 任务不会在调度器开始前和暂停中被触发 (任务没有进行中).

你可以看到, 这个Quartz.NET 相当的简单, 在教程2当中我们可以快速浏览下任务和触发器. 这样你可以更全面的理解这个例子了