目前 Quartz.NET 最新版本已經(jīng) 3.0.4 ,從 3.0 開始已經(jīng)支持 .NET Core,所以在 .NET 版本 和 部署環(huán)境 上都有更多的選擇。下面分別介紹基于.NET Framework 的 Windows 環(huán)境部署 和 基于.NET Core 的 Linux 環(huán)境部署。
Windows
在介紹 Windows 環(huán)境部署之前需要先閱讀一下 Topshelf 秒建 Windows 服務(wù)。通過 Topshelf 我們非??焖俨渴鹨粋€(gè) Windows 服務(wù)。
定義 TestSchedule 如下,代碼功能和之前的 Demo 沒什么區(qū)別,只是將里 Start 和 Shutdown 定義在了方法中。
public class TestSchedule
{
readonly IScheduler scheduler = null;
public TestSchedule()
{
// 創(chuàng)建作業(yè)調(diào)度器
scheduler = new StdSchedulerFactory().GetScheduler().Result;
var jobDataMap = new JobDataMap();
jobDataMap.Add("times", "1");
// 創(chuàng)建一個(gè)作業(yè)
IJobDetail job = JobBuilder.Create<TestJob>()
.WithIdentity("job1", "jobGroup1")
.UsingJobData(jobDataMap)
.Build();
// 創(chuàng)建一個(gè)觸發(fā)器
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "triggerGroup1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(1)
.WithRepeatCount(10))
.Build();
scheduler.ScheduleJob(job, trigger).Wait();
}
public void Start()
{
scheduler.Start().Wait();
}
public void Stop()
{
scheduler.Shutdown().Wait();
}
}
Main 方法中添加如下設(shè)置:
static void Main(string[] args)
{
// 配置和運(yùn)行宿主服務(wù)
HostFactory.Run(x =>
{
// 指定服務(wù)類型。這里設(shè)置為 TestSchedule
x.Service<TestSchedule>(s =>
{
// 通過 new TestSchedule() 構(gòu)建一個(gè)服務(wù)實(shí)例
s.ConstructUsing(name => new TestSchedule());
// 當(dāng)服務(wù)啟動(dòng)后執(zhí)行什么
s.WhenStarted(tc => tc.Start());
// 當(dāng)服務(wù)停止后執(zhí)行什么
s.WhenStopped(tc => tc.Stop());
});
// 服務(wù)用本地系統(tǒng)賬號(hào)來運(yùn)行
x.RunAsLocalSystem();
// 服務(wù)描述信息
x.SetDescription("TestSchedule");
// 服務(wù)顯示名稱
x.SetDisplayName("TestScheduleService");
// 服務(wù)名稱
x.SetServiceName("TestScheduleService");
});
}
開發(fā)環(huán)境下直接通過 F5 運(yùn)行調(diào)試。如果希望部署成服務(wù),只需要在 bin 目錄下執(zhí)行:
xxx.exe install

服務(wù)啟動(dòng)后我們通過日志記錄運(yùn)行結(jié)果如下:

Linux
測(cè)試代碼基于.Net Core 2.0 ,最終通過 Docker 來部署到 Linux 上。和 Windows 方式類似,創(chuàng)建一個(gè)控制臺(tái)應(yīng)用程序,Program.cs 主要代碼如下:
class Program
{
private static readonly ManualResetEvent manualResetEvent = new ManualResetEvent(false);
private static TestSchedule testSchedule;
static void Main(string[] args)
{
testSchedule = new TestSchedule();
// 開啟新線程執(zhí)行 Schedule
Task.Run(Start);
Console.CancelKeyPress += (sender, e) =>
{
Task.Run(StopSilo);
};
AppDomain.CurrentDomain.ProcessExit += (s, e) =>
{
Task.Run(StopSilo);
};
// 進(jìn)入阻塞狀態(tài),開始等待喚醒信號(hào)。(防止程序直接退出)
manualResetEvent.WaitOne();
}
private static async Task Start()
{
await testSchedule.Start();
Console.WriteLine("started");
}
private static async Task StopSilo()
{
await testSchedule.Stop();
Console.WriteLine("stopped");
// 取消阻塞狀態(tài),發(fā)出喚醒信號(hào)
manualResetEvent.Set();
}
}
這里需要注意 ManualResetEvent 的使用,它主要用于多線程協(xié)同和進(jìn)程操作,這里可以理解為 Quartz 的執(zhí)行提供守護(hù)進(jìn)程。
如果是Windows用戶,可以把程序 Build 后打包到 Linux 上生成鏡像,也可以通過 Docker for Windows 在本地生成鏡像。
創(chuàng)建 Dockerfile:
FROM microsoft/aspnetcore:2.0
COPY bin/Release/PublishOutput /app/
WORKDIR /app
ENTRYPOINT ["dotnet", "/app/App_NetCore.dll"]
- 通過 FROM 指定了需要的基礎(chǔ)鏡像 aspnetcore2.0 環(huán)境;
- 將發(fā)布好的代碼 COPY 到鏡像內(nèi)的 /app/ 目錄下( bin/Release/PublishOutput 是程序默認(rèn)發(fā)布的地址);
- 指定 /app/ 為工作目錄;
- 通過 ENTRYPOINT 指定程序啟動(dòng)運(yùn)行的命令。
接下來分別執(zhí)行以下幾條命令:
// docker build 默認(rèn)會(huì)根據(jù)當(dāng)前目錄下的 Dockerfile 文件生成鏡像,這里指定鏡像名為 beckjin/test-quartznet-local
docker build -t beckjin/test-quartznet-local .
// 通過 docker tag 給 beckjin/test-quartznet-local 最新 build 的版本打上一個(gè)標(biāo)簽 beckjin/test-quartznet:0.0.1(可以理解為版本)
docker tag beckjin/test-quartznet-local:latest beckjin/test-quartznet:0.0.1
// 登錄 docker hub 賬號(hào)
docker login -u xxx -p xxx
// 將鏡像推到 docker hub 上
docker push beckjin/test-quartznet:0.0.1
// 執(zhí)行 beckjin/test-quartznet:0.0.1 鏡像
docker run beckjin/test-quartznet:0.0.1
因?yàn)檫@個(gè)例子比較簡(jiǎn)單,這里直接使用 docker run 來執(zhí)行。結(jié)果如下:
