Quartz.NET是一個開源的作業調度框架,非常適合在平時的工作中,定時輪詢數據庫同步,定時郵件通知,定時處理數據等。Quartz.NET允許開發人員根據時間間隔(或天)來調度作業。它實現了作業和觸發器的多對多關係,還能把多個作業與不同的觸發器關聯。整合了 Quartz.NET的應用程序可以重用來自不同事件的作業,還可以爲一個事件組合多個作業。
官方學習文檔:http://www.quartz-scheduler.net/documentation/index.html
使用實例介紹:https://www.quartz-scheduler.net/documentation/quartz-3.x/quick-start.html
官方使用教程:Quartz.NET - Quartz.NET 3.x 教程
官方教程譯文:Quartz.NET 3.x 教程
Quartz.NET的快速入門指南
歡迎來到Quartz.NET的快速入門指南。當您閱讀本指南時,您將看到以下詳細信息:
- 下載Quartz.NET
- 安裝Quartz.NET
- 根據您自己的特殊需要配置Quartz
- 啓動示例應用程序
一、下載並安裝
您可以下載zip文件,也可以使用NuGet包。NuGet包只包含運行Quartz所需的二進制文件。zip文件附帶源代碼、示例和Quartz。NET服務器示例應用程序。
1、安裝包版本
簡約版:下載Quartz.NET,將其解壓縮到某個地方,從bin目錄獲取Quartz.dll和Common.Logging.dll並開始使用它們。
Quartz只依賴於稱爲Common的第三方庫。日誌(其中包含日誌抽象,允許您使用最適合您的日誌提供程序)。你需要在你的應用程序二進制文件旁邊有Quartz.dll和Commong.Logging.dll才能成功運行Quartz.NET。所以只需將它們作爲引用添加到使用它們的Visual Studio項目中。您可以從path bin\your-target-frame -version\release\Quartz中提取的歸檔文件中找到這些dll。
2、NuGet包安裝
只需啓動Visual Studio(使用NuGet安裝),並從包管理器擴展名中添加對包Quartz的引用:
- 右鍵單擊項目的引用,並選擇Manage NuGet Packages…
- 從左側選擇在線類別
- 在右上角輸入Quartz,搜索並回車
- 選擇Quartz.NET從搜索結果中點擊安裝
- 完成了!
或從NuGet命令行:
Install-Package Quartz
如果您想添加JSON序列化,只需添加Quartz.Serialization.Json以同樣的方式打包。
3、Configuration 配置
這纔是重點!Quartz.NET是一個非常可配置的庫。提供Quartz有三種方式(它們並不相互排斥).NET配置信息:
- 通過向調度器工廠提供NameValueCollection參數,以編程方式實現
- 通過標準youapp.exe。配置配置文件使用quartz-element(完整的.net框架)
- quartz.config在你的應用程序的根目錄下(適用於.net核心和完整的.net框架)
您可以在Quartz.NET zip文件中找到所有這些備選方案的示例。
基本的Quartz.config是這樣的:
quartz.scheduler.instanceName = MyScheduler
quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz
quartz.threadPool.threadCount = 3
記住將Visual Studio的文件屬性頁上的Copy設置爲Output目錄,以便始終保持Copy值。否則,如果配置不在構建目錄中,將看不到它。
該配置創建的調度器具有以下特點:
- quartz.scheduler.instanceName —— 這個調度程序的名稱將是“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)
{
// 觸發器異步計算
RunProgram().GetAwaiter().GetResult();
}
private static async Task RunProgram()
{
try
{
// 從工廠獲取調度程序實例
NameValueCollection props = new NameValueCollection
{
{ "quartz.serializer.type", "binary" }
};
StdSchedulerFactory factory = new StdSchedulerFactory(props);
IScheduler scheduler = await factory.GetScheduler();
// 然後開始
await scheduler.Start();
// 線程休眠60秒,是爲了更好的觀察
await Task.Delay(TimeSpan.FromSeconds(60));
// 最後關閉調度程序
await scheduler.Shutdown();
}
catch (SchedulerException se)
{
await Console.Error.WriteLineAsync(se.ToString());
}
}
}
}
從Quartz 3.0開始,當scheduler. shutdown()之後沒有代碼可執行時,應用程序將終止,因爲不會有任何活動線程。如果您希望調度程序在任務完成後也能繼續運行,則應手動阻止退出應用程序。延遲和關機已經處理。
現在運行程序不會顯示任何內容。當10秒過去了,程序將會終止。讓我們向控制檯添加一些日誌記錄。
添加日誌記錄
LibLog可以配置爲使用不同的日誌框架;即Log4Net、NLog和Serilog。
當LibLog沒有檢測到任何其他日誌框架時,它將保持靜默。如果您還沒有準備好日誌框架,我們可以配置一個自定義日誌記錄器提供程序,它只記錄到控制檯並顯示輸出。
將下列代碼添加到 Program.cs
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.
我們需要一個簡單的測試作業來測試功能,讓我們創建輸出問候到控制檯的HelloJob。
public class HelloJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
await Console.Out.WriteLineAsync("來自HelloJob的問候!");
}
}
您需要在Start()方法之後、在Task.Delay之前編寫代碼。
// 定義作業並將其綁定到HelloJob類
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithIdentity("job1", "group1")
.Build();
// 觸發作業現在運行,然後每10秒重複一次
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(10)
.RepeatForever())
.Build();
// 告訴quartz使用我們的觸發器來安排工作
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("按任意鍵關閉應用程序");
Console.ReadKey();
}
private static async Task RunProgramRunExample()
{
try
{
// 從工廠獲取調度程序實例
NameValueCollection props = new NameValueCollection
{
{ "quartz.serializer.type", "binary" }
};
StdSchedulerFactory factory = new StdSchedulerFactory(props);
IScheduler scheduler = await factory.GetScheduler();
// 然後開始
await scheduler.Start();
// 定義作業並將其綁定到HelloJob類
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithIdentity("job1", "group1")
.Build();
// 觸發作業現在運行,然後每10秒重複一次
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(10)
.RepeatForever())
.Build();
// 告訴quartz使用我們的觸發器來安排工作
await scheduler.ScheduleJob(job, trigger);
// 線程休眠60秒,是爲了更好的觀察
await Task.Delay(TimeSpan.FromSeconds(60));
// 最後關閉調度程序
await scheduler.Shutdown();
}
catch (SchedulerException se)
{
Console.WriteLine(se);
}
}
// 簡單的日誌提供程序來獲取控制檯的內容
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("來自 HelloJob 的問候!");
}
}
}
現在去探索一下Quartz.NET吧!您可以繼續閱讀教程。