Quartz.net 3.x使用总结(二)——Db持久化和集群

  上一篇简单介绍了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等的增/删/改/查/暂停/恢复即可。

原文地址:https://www.cnblogs.com/wyy1234/p/10347049.html

时间: 2024-10-16 08:58:42

Quartz.net 3.x使用总结(二)——Db持久化和集群的相关文章

quartz.net持久化和集群【转】

在实际使用quartz.net中.持久化能保证实例重启后job不丢失. 集群能均衡服务器压力和解决单点问题. quartz.net在这二块配置都比较方便,来看下. 一:持久化 quartz.net的持久化,是把job.trigger一些信息存储到数据库里面,以解决内存存储重启丢失. 1:  下载sql脚本.  https://github.com/quartznet/quartznet/blob/master/database/tables/tables_sqlServer.sql 2:  创建

quartz.net持久化和集群--(四)

介绍 在实际使用quartz.net中.持久化能保证实例重启后job不丢失. 集群能均衡服务器压力和解决单点问题. quartz.net在这二块配置都比较方便,来看下. 一:持久化 quartz.net的持久化,是把job.trigger一些信息存储到数据库里面,以解决内存存储重启丢失. 1:  下载sql脚本.  https://github.com/quartznet/quartznet/blob/master/database/tables/tables_sqlServer.sql 2:

OpenFire源码学习之二十九:集群

集群 Openfire的给集群提供了多种方案.一种是基于Hazelcast插件,还有基于Oracle的coherence插件. Linux集群配置 一.修改配置文件 /etc/hosts文件 openfire1 192.168.2.104 openfire2192.168.2.240 每台主机都需要配置 二.添加jar包 将coherence.jar.coherence-work.jar.tangosol.jar添加到lib目录 将clustering.jar放到plugins下面 Hazelc

Flume NG 学习笔记(二)单机与集群Flume 配置

下面的内容基本来自官网:http://flume.apache.org/FlumeUserGuide.html 本文使用的是最新版本的apache flume 1.5,安装完Flume然后测试下Flume是否可以用,在Flume目录下用以下语句测试: bin/flume-ng agent -n$agent_name -c conf -f conf/flume-conf.properties.template 结果如图显示: Ok,我们接下去看下面常用架构.功能配置示例 一.最简单的单一代理Flu

ELK+Filebeat+Nginx集中式日志解决方案(二)——添加ElasticSearch集群

一.使用说明: Elasticsearch插件:  Elasticsearch常用的几个插件为: # head # 地址  https://github.com/mobz/elasticsearch-head mobz/elasticsearch-head # kopf # 地址  https://github.com/lmenezes/elasticsearch-kopf lmenezes/elasticsearch-kopf # bigdesk # 地址 https://github.com

Quartz.net持久化与集群部署开发详解

序言 我前边有几篇文章有介绍过quartz的基本使用语法与类库.但是他的执行计划都是被写在本地的xml文件中.无法做集群部署,我让它看起来脆弱不堪,那是我的罪过. 但是quart.net是经过许多大项目的锤炼,走到啦今天,支持集群高可用的开发方案那是一定的,今天我就给小结下我的quartz.net开发升级过程. Quartz.net的数据库表结构 如果支持集群与持久化,单靠本机的内存和xml来保存计算任务调度的各种状态值,可想而知,是困难的.所以支持数据库这样的解决方案,OpenSymphony

Hadoop小兵笔记【二】Hadoop分布式集群扩展实战经验

一.集群原先配置: 主机名sparkMaster,Ubuntu12.04-32 ,用户名Root , 内存4g    (只用于任务调度和分配,不做计算节点) 从机名sparkSlave1,Ubuntu12.04-32 ,用户名Root , 内存4g    (计算节点) 从机名sparkSlave2,Ubuntu12.04-32 ,用户名Root , 内存1.7g (计算节点) 二.扩展原因:计算数据量增大,原先的两个工作节点已不不能满足实时性的需求,由于实验室计算资源有限,故将原先的调度节点也增

【转】Quartz.net持久化与集群部署开发详解

转自:http://www.cnblogs.com/knowledgesea/p/5145239.html 序言 我前边有几篇文章有介绍过quartz的基本使用语法与类库.但是他的执行计划都是被写在本地的xml文件中.无法做集群部署,我让它看起来脆弱不堪,那是我的罪过. 但是quart.net是经过许多大项目的锤炼,走到啦今天,支持集群高可用的开发方案那是一定的,今天我就给小结下我的quartz.net开发升级过程. Quartz.net的数据库表结构 如果支持集群与持久化,单靠本机的内存和xm

六十二、负载均衡集群介绍、LVS介绍、LVS的调度算法、LVS NAT模式搭建

一.负载均衡集群介绍 主流开源软件LVS.keepalived.haproxy.nginx等 其中LVS属于4层(网络OSI 7层模型),nginx属于7层,haproxy既可以认为是4层,也可以当做7层使用. OSI简介:OSI采用了分层的结构化技术,共分七层,物理层.数据链路层.网络层.传输层.会话层.表示层.应用层. keepalived的负载均衡功能其实就是lvs,内置的功能. lvs这种4层的负载均衡是可以分发除80外的其他端口通信的,比如MySQL的,而nginx仅仅支持http,h