上一篇簡單介紹了Quartz.net的概念和基本用法,這一篇記錄一下Quartz.net通過資料庫持久化Trigger和Jobs等資料,並簡單配置Quartz.net的叢集。
1.JobStore介紹
學習持久化和叢集前我們先了解一下Quartz.net中的JobStore,JobStore用於追蹤任務排程相關的所有資料,如Job,Trigger,Claendar等。Quartz.net 提供了兩種JobStore:RAMJobStore,AdoJobStore。
RAMJobStore
RAMJobStore是最簡單的JobStore,顧名思義這種JobStore將所有的資料都存放在記憶體中,這也是它執行速度快的原因,但是弊端也很明顯:一旦應用結束或者遇到斷電所有的資料都會丟失。RAMJobStore是預設的JobStore,我們也已通過下邊的程式碼來顯式設定使用的JobStore為RAMJobStore。
quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz
AdoJobStore
AdoJobStore通過Ado.net將資料儲存在資料庫中,因此可以解決斷電資料丟失的問題,但是因為要讀寫資料庫所以效率相對較低。AdoJobStore官方支援的資料庫有:MySql,SqlServer,Sqllite,Oracle等,當前AdoJobStore只有一種型別JobStoreTX,這一點不同於Jave版本,java版本還有JobStoreCMT型別。
2.Db持久化和叢集配置
Quartz.net配置資料庫持久化和叢集比較容易,可以分為簡單的兩步:
第一步:新增資料庫表
我們首先要在資料庫中新增一系列的表(在Quartz專案的database/tables資料夾下可以找到各種資料庫表的生成指令碼,Git地址https://github.com/quartznet/quartznet/tree/master/database/tables)。以Sqlserver為例,Sqlserver的資料表生成指令碼如下:
-- this script is for SQL Server and Azure SQL create database [QuartzDb] go USE [QuartzDb] GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) ALTER TABLE [dbo].[QRTZ_TRIGGERS] DROP CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] DROP CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS GO IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_QRTZ_JOB_LISTENERS_QRTZ_JOB_DETAILS]') AND parent_object_id = OBJECT_ID(N'[dbo].[QRTZ_JOB_LISTENERS]')) ALTER TABLE [dbo].[QRTZ_JOB_LISTENERS] DROP CONSTRAINT [FK_QRTZ_JOB_LISTENERS_QRTZ_JOB_DETAILS] IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_QRTZ_TRIGGER_LISTENERS_QRTZ_TRIGGERS]') AND parent_object_id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGER_LISTENERS]')) ALTER TABLE [dbo].[QRTZ_TRIGGER_LISTENERS] DROP CONSTRAINT [FK_QRTZ_TRIGGER_LISTENERS_QRTZ_TRIGGERS] IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CALENDARS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) DROP TABLE [dbo].[QRTZ_CALENDARS] GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CRON_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) DROP TABLE [dbo].[QRTZ_CRON_TRIGGERS] GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_BLOB_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) DROP TABLE [dbo].[QRTZ_BLOB_TRIGGERS] GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_FIRED_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) DROP TABLE [dbo].[QRTZ_FIRED_TRIGGERS] GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_PAUSED_TRIGGER_GRPS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) DROP TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] GO IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_JOB_LISTENERS]') AND type in (N'U')) DROP TABLE [dbo].[QRTZ_JOB_LISTENERS] IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SCHEDULER_STATE]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) DROP TABLE [dbo].[QRTZ_SCHEDULER_STATE] GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_LOCKS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) DROP TABLE [dbo].[QRTZ_LOCKS] GO IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGER_LISTENERS]') AND type in (N'U')) DROP TABLE [dbo].[QRTZ_TRIGGER_LISTENERS] IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_JOB_DETAILS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) DROP TABLE [dbo].[QRTZ_JOB_DETAILS] GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPLE_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) DROP TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPROP_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) DROP TABLE [dbo].QRTZ_SIMPROP_TRIGGERS GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) DROP TABLE [dbo].[QRTZ_TRIGGERS] GO CREATE TABLE [dbo].[QRTZ_CALENDARS] ( [SCHED_NAME] [NVARCHAR] (120) NOT NULL , [CALENDAR_NAME] [NVARCHAR] (200) NOT NULL , [CALENDAR] [VARBINARY](MAX) NOT NULL ) GO CREATE TABLE [dbo].[QRTZ_CRON_TRIGGERS] ( [SCHED_NAME] [NVARCHAR] (120) NOT NULL , [TRIGGER_NAME] [NVARCHAR] (150) NOT NULL , [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL , [CRON_EXPRESSION] [NVARCHAR] (120) NOT NULL , [TIME_ZONE_ID] [NVARCHAR] (80) ) GO CREATE TABLE [dbo].[QRTZ_FIRED_TRIGGERS] ( [SCHED_NAME] [NVARCHAR] (120) NOT NULL , [ENTRY_ID] [NVARCHAR] (140) NOT NULL , [TRIGGER_NAME] [NVARCHAR] (150) NOT NULL , [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL , [INSTANCE_NAME] [NVARCHAR] (200) NOT NULL , [FIRED_TIME] [BIGINT] NOT NULL , [SCHED_TIME] [BIGINT] NOT NULL , [PRIORITY] [INTEGER] NOT NULL , [STATE] [NVARCHAR] (16) NOT NULL, [JOB_NAME] [NVARCHAR] (150) NULL , [JOB_GROUP] [NVARCHAR] (150) NULL , [IS_NONCONCURRENT] BIT NULL , [REQUESTS_RECOVERY] BIT NULL ) GO CREATE TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] ( [SCHED_NAME] [NVARCHAR] (120) NOT NULL , [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL ) GO CREATE TABLE [dbo].[QRTZ_SCHEDULER_STATE] ( [SCHED_NAME] [NVARCHAR] (120) NOT NULL , [INSTANCE_NAME] [NVARCHAR] (200) NOT NULL , [LAST_CHECKIN_TIME] [BIGINT] NOT NULL , [CHECKIN_INTERVAL] [BIGINT] NOT NULL ) GO CREATE TABLE [dbo].[QRTZ_LOCKS] ( [SCHED_NAME] [NVARCHAR] (120) NOT NULL , [LOCK_NAME] [NVARCHAR] (40) NOT NULL ) GO CREATE TABLE [dbo].[QRTZ_JOB_DETAILS] ( [SCHED_NAME] [NVARCHAR] (120) NOT NULL , [JOB_NAME] [NVARCHAR] (150) NOT NULL , [JOB_GROUP] [NVARCHAR] (150) NOT NULL , [DESCRIPTION] [NVARCHAR] (250) NULL , [JOB_CLASS_NAME] [NVARCHAR] (250) NOT NULL , [IS_DURABLE] BIT NOT NULL , [IS_NONCONCURRENT] BIT NOT NULL , [IS_UPDATE_DATA] BIT NOT NULL , [REQUESTS_RECOVERY] BIT NOT NULL , [JOB_DATA] [VARBINARY](MAX) NULL ) GO CREATE TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ( [SCHED_NAME] [NVARCHAR] (120) NOT NULL , [TRIGGER_NAME] [NVARCHAR] (150) NOT NULL , [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL , [REPEAT_COUNT] [INTEGER] NOT NULL , [REPEAT_INTERVAL] [BIGINT] NOT NULL , [TIMES_TRIGGERED] [INTEGER] NOT NULL ) GO CREATE TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ( [SCHED_NAME] [NVARCHAR] (120) NOT NULL , [TRIGGER_NAME] [NVARCHAR] (150) NOT NULL , [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL , [STR_PROP_1] [NVARCHAR] (512) NULL, [STR_PROP_2] [NVARCHAR] (512) NULL, [STR_PROP_3] [NVARCHAR] (512) NULL, [INT_PROP_1] [INT] NULL, [INT_PROP_2] [INT] NULL, [LONG_PROP_1] [BIGINT] NULL, [LONG_PROP_2] [BIGINT] NULL, [DEC_PROP_1] [NUMERIC] (13,4) NULL, [DEC_PROP_2] [NUMERIC] (13,4) NULL, [BOOL_PROP_1] BIT NULL, [BOOL_PROP_2] BIT NULL, [TIME_ZONE_ID] [NVARCHAR] (80) NULL ) GO CREATE TABLE [dbo].[QRTZ_BLOB_TRIGGERS] ( [SCHED_NAME] [NVARCHAR] (120) NOT NULL , [TRIGGER_NAME] [NVARCHAR] (150) NOT NULL , [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL , [BLOB_DATA] [VARBINARY](MAX) NULL ) GO CREATE TABLE [dbo].[QRTZ_TRIGGERS] ( [SCHED_NAME] [NVARCHAR] (120) NOT NULL , [TRIGGER_NAME] [NVARCHAR] (150) NOT NULL , [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL , [JOB_NAME] [NVARCHAR] (150) NOT NULL , [JOB_GROUP] [NVARCHAR] (150) NOT NULL , [DESCRIPTION] [NVARCHAR] (250) NULL , [NEXT_FIRE_TIME] [BIGINT] NULL , [PREV_FIRE_TIME] [BIGINT] NULL , [PRIORITY] [INTEGER] NULL , [TRIGGER_STATE] [NVARCHAR] (16) NOT NULL , [TRIGGER_TYPE] [NVARCHAR] (8) NOT NULL , [START_TIME] [BIGINT] NOT NULL , [END_TIME] [BIGINT] NULL , [CALENDAR_NAME] [NVARCHAR] (200) NULL , [MISFIRE_INSTR] [INTEGER] NULL , [JOB_DATA] [VARBINARY](MAX) NULL ) GO ALTER TABLE [dbo].[QRTZ_CALENDARS] WITH NOCHECK ADD CONSTRAINT [PK_QRTZ_CALENDARS] PRIMARY KEY CLUSTERED ( [SCHED_NAME], [CALENDAR_NAME] ) GO ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] WITH NOCHECK ADD CONSTRAINT [PK_QRTZ_CRON_TRIGGERS] PRIMARY KEY CLUSTERED ( [SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP] ) GO ALTER TABLE [dbo].[QRTZ_FIRED_TRIGGERS] WITH NOCHECK ADD CONSTRAINT [PK_QRTZ_FIRED_TRIGGERS] PRIMARY KEY CLUSTERED ( [SCHED_NAME], [ENTRY_ID] ) GO ALTER TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] WITH NOCHECK ADD CONSTRAINT [PK_QRTZ_PAUSED_TRIGGER_GRPS] PRIMARY KEY CLUSTERED ( [SCHED_NAME], [TRIGGER_GROUP] ) GO ALTER TABLE [dbo].[QRTZ_SCHEDULER_STATE] WITH NOCHECK ADD CONSTRAINT [PK_QRTZ_SCHEDULER_STATE] PRIMARY KEY CLUSTERED ( [SCHED_NAME], [INSTANCE_NAME] ) GO ALTER TABLE [dbo].[QRTZ_LOCKS] WITH NOCHECK ADD CONSTRAINT [PK_QRTZ_LOCKS] PRIMARY KEY CLUSTERED ( [SCHED_NAME], [LOCK_NAME] ) GO ALTER TABLE [dbo].[QRTZ_JOB_DETAILS] WITH NOCHECK ADD CONSTRAINT [PK_QRTZ_JOB_DETAILS] PRIMARY KEY CLUSTERED ( [SCHED_NAME], [JOB_NAME], [JOB_GROUP] ) GO ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] WITH NOCHECK ADD CONSTRAINT [PK_QRTZ_SIMPLE_TRIGGERS] PRIMARY KEY CLUSTERED ( [SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP] ) GO ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] WITH NOCHECK ADD CONSTRAINT [PK_QRTZ_SIMPROP_TRIGGERS] PRIMARY KEY CLUSTERED ( [SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP] ) GO ALTER TABLE [dbo].[QRTZ_TRIGGERS] WITH NOCHECK ADD CONSTRAINT [PK_QRTZ_TRIGGERS] PRIMARY KEY CLUSTERED ( [SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP] ) GO ALTER TABLE [dbo].QRTZ_BLOB_TRIGGERS WITH NOCHECK ADD CONSTRAINT [PK_QRTZ_BLOB_TRIGGERS] PRIMARY KEY CLUSTERED ( [SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP] ) GO ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY ( [SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP] ) REFERENCES [dbo].[QRTZ_TRIGGERS] ( [SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP] ) ON DELETE CASCADE GO ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY ( [SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP] ) REFERENCES [dbo].[QRTZ_TRIGGERS] ( [SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP] ) ON DELETE CASCADE GO ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY ( [SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP] ) REFERENCES [dbo].[QRTZ_TRIGGERS] ( [SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP] ) ON DELETE CASCADE GO ALTER TABLE [dbo].[QRTZ_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS] FOREIGN KEY ( [SCHED_NAME], [JOB_NAME], [JOB_GROUP] ) REFERENCES [dbo].[QRTZ_JOB_DETAILS] ( [SCHED_NAME], [JOB_NAME], [JOB_GROUP] ) GO CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP) CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP) CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME) CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP) CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE) CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE) CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE) CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME) CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME) CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME) CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE) CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE) CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME) CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY) CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP) CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP) CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP) GO
在Sqlserver管理器中新建查詢,貼上上邊的指令碼,執行即可生成Quartz的資料庫表,資料庫的結構如下:
第二部:配置QuartzFactory屬性,直接看程式碼:
class Program { public static void Main(string[] args) { NameValueCollection pars = new NameValueCollection { //scheduler名字 ["quartz.scheduler.instanceName"] = "MyScheduler", //執行緒池個數 ["quartz.threadPool.threadCount"] = "20", //型別為JobStoreXT,事務 ["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz", //JobDataMap中的資料都是字串 //["quartz.jobStore.useProperties"] = "true", //資料來源名稱 ["quartz.jobStore.dataSource"] = "myDS", //資料表名字首 ["quartz.jobStore.tablePrefix"] = "QRTZ_", //使用Sqlserver的Ado操作代理類 ["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz", //資料來源連線字串 ["quartz.dataSource.myDS.connectionString"] = "Server=[yourserver];Database=quartzDb;Uid=sa;Pwd=[yourpass]", //資料來源的資料庫 ["quartz.dataSource.myDS.provider"] = "SqlServer", //序列化型別 ["quartz.serializer.type"] = "json",//binary //自動生成scheduler例項ID,主要為了保證叢集中的例項具有唯一標識 ["quartz.scheduler.instanceId"] = "AUTO", //是否配置叢集 ["quartz.jobStore.clustered"] = "true", }; StdSchedulerFactory factory = new StdSchedulerFactory(pars); IScheduler scheduler = factory.GetScheduler().Result; scheduler.Start(); IJobDetail job = JobBuilder.Create<MyJob>() .WithIdentity("job1", "g1") .Build(); ITrigger trigger = TriggerBuilder.Create().WithIdentity("trigger1", "g1").WithCronSchedule("0/1 * * * * ?").Build(); if (scheduler.CheckExists(job.Key).Result) { scheduler.DeleteJob(job.Key).Wait(); } scheduler.ScheduleJob(job, trigger).Wait(); } } public class MyJob : IJob { public async Task Execute(IJobExecutionContext context) { await Task.Run(() => { Console.WriteLine($"hello! 當前時間:{DateTime.Now}"); Console.WriteLine($"觸發時間:{context.ScheduledFireTimeUtc?.LocalDateTime},下次觸發時間:{context.NextFireTimeUtc?.LocalDateTime}"); Console.WriteLine(); }); } }
上邊的程式碼配置資訊在程式碼中都有註釋,這個栗子實現了一個簡單的任務排程:每秒列印一次任務的觸發時間和下次觸發時間。然後執行專案即可,到這裡Db持久化和叢集都配置完成了。執行程式Quartz會自動在資料庫中記錄排程任務相關的資料
Quartz自動向資料庫寫入的trigger資訊:
Quartz自動向資料庫寫入的Job資訊:
程式執行結果:
到這裡我們看到了Db持久化已經實現了,但是上邊的栗子,我們在程式碼中通過 ["quartz.jobStore.clustered"] = "true" 配置了叢集,這個有什麼用呢?
首先新增一個debug資料夾的副本
然後執行這兩個資料夾下的xxx.exe檔案(如果使用的是.net core,生成的是xxx.dll檔案,進入dll檔案所在目錄,命令列執行 dotnet xxx.dll 即可啟動),執行結果如下:
如上所示,執行兩個xxx.exe(core中是dll)後,原檔案和副本在同一時間只有一個在執行,所以我們排程的任務沒有重複執行。如果我們關掉正在執行的那個程式,那麼另一個程式會開始執行。我們可以得出結論:Quartz的叢集並不會造成任務重複執行,而且當一個伺服器掛了後,另一個伺服器會自動開始執行,這種機制大大增加了任務排程的容災效能。
3.一些需要注意的地方
1.Quartz3.x支援async和await,為提高效能,我們最好將Job中的Execute方法都寫成非同步方法;
2.不管使用的是RAMJobStore還是AdoJobStore,千萬不要通過程式碼來直接操作JobStore(比如我們直接通過程式碼修改資料庫中的資料),JobStore讓Quartz自動操作即可。無論使用場景是web應用還是桌面程式,我們只使用Scheduler提供的介面方法來實現Job和Trigger等的增/刪/改/查/暫停/恢復即可。