一般拿Timer和Quartz相比较的,简直就是对Quartz的侮辱,两者的功能根本就不在一个层级上,如本篇介绍的Quartz强大的集群机制,可以采用基于

sqlserver,mysql的集群方案,当然还可以在第三方插件的基础上实现quartz序列化到热炒的mongodb,redis,震撼力可想而知,接下来本篇就和大家聊

一聊怎么搭建基于sqlserver的quartz集群,实现这么一种双机热备的强大功能。

一:下载sqlserver版的建表脚本

    首先大家可以通过github上搜索quartz的源代码,在源码项目的/database/tables目录下,可以找到firebird,oracle,mysql,sqlserver等建库脚本,

本篇只需拿取sqlserver版本即可。 https://github.com/quartznet/quartznet/tree/master/database/tables  如下图所示

从上面的截图中可以看到,我接下来要做的事情就是增加一个你需要创建的database名字,这里取为:【quartz】,完整的脚本如下:

 -- this script is for SQL Server and Azure SQL

 CREATE DATABASE [quartz]
GO USE [quartz]
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] [IMAGE] 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] [IMAGE] 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,
)
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] [IMAGE] 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] [IMAGE] 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

二:配置quartz的集群参数

当我们写var scheduler = StdSchedulerFactory.GetDefaultScheduler()这段代码的时候,如果大家看过源码的话,会知道这个GetScheduler的

过程中有一个初始化方法【Instantiate】方法,此方法中你会发现在做DBProvider的时候会需要几个参数来初始化DB的,比如下面看到的几个标红属性。

             IList<string> dsNames = cfg.GetPropertyGroups(PropertyDataSourcePrefix);
foreach (string dataSourceName in dsNames)
{
string datasourceKey = "{0}.{1}".FormatInvariant(PropertyDataSourcePrefix, dataSourceName);
NameValueCollection propertyGroup = cfg.GetPropertyGroup(datasourceKey, true);
PropertiesParser pp = new PropertiesParser(propertyGroup); Type cpType = loadHelper.LoadType(pp.GetStringProperty(PropertyDbProviderType, null)); // custom connectionProvider...
if (cpType != null)
{
IDbProvider cp;
try
{
cp = ObjectUtils.InstantiateType<IDbProvider>(cpType);
}
catch (Exception e)
{
initException = new SchedulerException("ConnectionProvider of type '{0}' could not be instantiated.".FormatInvariant(cpType), e);
throw initException;
} try
{
// remove the type name, so it isn't attempted to be set
pp.UnderlyingProperties.Remove(PropertyDbProviderType); ObjectUtils.SetObjectProperties(cp, pp.UnderlyingProperties);
cp.Initialize();
}
catch (Exception e)
{
initException = new SchedulerException("ConnectionProvider type '{0}' props could not be configured.".FormatInvariant(cpType), e);
throw initException;
} dbMgr = DBConnectionManager.Instance;
dbMgr.AddConnectionProvider(dataSourceName, cp);
}
else
{
string dsProvider = pp.GetStringProperty(PropertyDataSourceProvider, null);
string dsConnectionString = pp.GetStringProperty(PropertyDataSourceConnectionString, null);
string dsConnectionStringName = pp.GetStringProperty(PropertyDataSourceConnectionStringName, null); if (dsConnectionString == null && !String.IsNullOrEmpty(dsConnectionStringName))
{ ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings[dsConnectionStringName];
if (connectionStringSettings == null)
{
initException = new SchedulerException("Named connection string '{0}' not found for DataSource: {1}".FormatInvariant(dsConnectionStringName, dataSourceName));
throw initException;
}
dsConnectionString = connectionStringSettings.ConnectionString;
} if (dsProvider == null)
{
initException = new SchedulerException("Provider not specified for DataSource: {0}".FormatInvariant(dataSourceName));
throw initException;
}
if (dsConnectionString == null)
{
initException = new SchedulerException("Connection string not specified for DataSource: {0}".FormatInvariant(dataSourceName));
throw initException;
}
try
{
DbProvider dbp = new DbProvider(dsProvider, dsConnectionString);
dbp.Initialize(); dbMgr = DBConnectionManager.Instance;
dbMgr.AddConnectionProvider(dataSourceName, dbp);
}
catch (Exception exception)
{
initException = new SchedulerException("Could not Initialize DataSource: {0}".FormatInvariant(dataSourceName), exception);
throw initException;
}
}
}

接下来的问题就是这几个属性是如何配置进去的,仔细观察上面代码,你会发现所有的配置的源头都来自于cfg变量,ok,接下来你可以继续翻看代码,相信

你会看到有一个Initialize方法就是做cfg变量的初始化,如下代码所示:

   public void Initialize()
{
// short-circuit if already initialized
if (cfg != null)
{
return;
}
if (initException != null)
{
throw initException;
} NameValueCollection props = (NameValueCollection) ConfigurationManager.GetSection(ConfigurationSectionName); string requestedFile = QuartzEnvironment.GetEnvironmentVariable(PropertiesFile); string propFileName = requestedFile != null && requestedFile.Trim().Length > 0 ? requestedFile : "~/quartz.config"; // check for specials
try
{
propFileName = FileUtil.ResolveFile(propFileName);
}
catch (SecurityException)
{
log.WarnFormat("Unable to resolve file path '{0}' due to security exception, probably running under medium trust");
propFileName = "quartz.config";
} if (props == null && File.Exists(propFileName))
{
// file system
try
{
PropertiesParser pp = PropertiesParser.ReadFromFileResource(propFileName);
props = pp.UnderlyingProperties;
Log.Info(string.Format("Quartz.NET properties loaded from configuration file '{0}'", propFileName));
}
catch (Exception ex)
{
Log.Error("Could not load properties for Quartz from file {0}: {1}".FormatInvariant(propFileName, ex.Message), ex);
} }
if (props == null)
{
// read from assembly
try
{
PropertiesParser pp = PropertiesParser.ReadFromEmbeddedAssemblyResource("Quartz.quartz.config");
props = pp.UnderlyingProperties;
Log.Info("Default Quartz.NET properties loaded from embedded resource file");
}
catch (Exception ex)
{
Log.Error("Could not load default properties for Quartz from Quartz assembly: {0}".FormatInvariant(ex.Message), ex);
}
}
if (props == null)
{
throw new SchedulerConfigException(
@"Could not find <quartz> configuration section from your application config or load default configuration from assembly.
Please add configuration to your application config file to correctly initialize Quartz.");
}
Initialize(OverrideWithSysProps(props));
}

仔细阅读上面的一串代码,你会发现,默认quartz参数配置来源于三个地方。

1. app.config中的section节点。

2. bin目录下的~/quartz.config文件。

3. 默认配置的NameValueCollection字典集合,也就是上一篇博客给大家做的一个演示。

我个人不怎么喜欢通过quartz.config文件进行配置,这样也容易写死,所以我还是喜欢使用最简单的NameValueCollection配置,因为它的数据源可来源

于第三方存储结构中,配置代码如下:

                 //1.首先创建一个作业调度池
var properties = new NameValueCollection();
//存储类型
properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"; //驱动类型
properties["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz"; //数据源名称
properties["quartz.jobStore.dataSource"] = "myDS"; //连接字符串
properties["quartz.dataSource.myDS.connectionString"] = @"server=.;Initial Catalog=quartz;Integrated Security=True";
//sqlserver版本
properties["quartz.dataSource.myDS.provider"] = "SqlServer-20"; //是否集群
properties["quartz.jobStore.clustered"] = "true";
properties["quartz.scheduler.instanceId"] = "AUTO";

上面的代码配置我都加过详细的注释,大家应该都能看得懂,而且这些配置就是这么定死的,没什么修改的空间,大家记住即可。

三:Job和Trigger定义

在集群中环境下,job和trigger的定义该怎么写的?大家也不要想的太复杂,注意一点就可以了,在Schedule一个Job时候,通过CheckExists判断一下

这个Job在Scheduler中是否已经存在了,如果存在,你就不能再次通过Schedule去重复调度一个Job就可以了。。。所以判断的代码也很简单,如下所示:

          IScheduler scheduler = factory.GetScheduler();

                 scheduler.Start();

                 var jobKey = JobKey.Create("myjob", "group");

                 if (scheduler.CheckExists(jobKey))
{
Console.WriteLine("当前job已经存在,无需调度:{0}", jobKey.ToString());
}
else
{
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithDescription("使用quartz进行持久化存储")
.StoreDurably()
.RequestRecovery()
.WithIdentity(jobKey)
.UsingJobData("count", )
.Build(); ITrigger trigger = TriggerBuilder.Create().WithSimpleSchedule(x => x.WithIntervalInSeconds().RepeatForever())
.Build(); scheduler.ScheduleJob(job, trigger); Console.WriteLine("调度进行中!!!");
}

上面这段代码,大家就可以部署在多台机器中了,是不是很简单?

四:强大的cluster完整演示

所有的初始化工作都做完了,接下来我们copy一份bin文件,同时打开两个console程序,如下所示,可以看到job任务只会被一个console调度,另外

一个在空等待。

然后你肯定很好奇的跑到sqlserver中去看看,是否已经有job和trigger的db存储,很开心吧,数据都有的。。。

好了,一切都是那么完美,接下来可以展示一下quartz集群下的高可用啦,如果某一个console挂了,那么另一台console会把这个任务给接过来,实

现强大的高可用。。。所以我要做的事情就是把console1关掉,再看看console2是不是可以开始调度job了???

完美,这个就是本篇给大家介绍的Quartz的Cluster集群,一台挂,另一台顶住,双机热备,当然这些console你可以部署在多台机器中,要做的就是保持各

个server的时间同步,因为quarz是依赖于本机server的时间,好了,本篇就先说到这里吧。

小礼物走一波,双击666。。。  完整代码:SimpleSchedulerApp.zip

使用sqlserver搭建高可用双机热备的Quartz集群部署【附源码】的更多相关文章

  1. 双机热备的Quartz集群

    sqlserver搭建高可用双机热备的Quartz集群部署[附源码]   一般拿Timer和Quartz相比较的,简直就是对Quartz的侮辱,两者的功能根本就不在一个层级上,如本篇介绍的Quartz ...

  2. heartbeat+DRBD 高可用 双机热备

    heartbeat+DRBD 高可用 双机热备 原创博文http://www.cnblogs.com/elvi/p/7658109.html ## heartbeat+DRBD 高可用 双机热备 # ...

  3. Nginx+keepalived 高可用双机热备(主从模式/双主模式)

    基础介绍负载均衡技术对于一个网站尤其是大型网站的web服务器集群来说是至关重要的!做好负载均衡架构,可以实现故障转移和高可用环境,避免单点故障,保证网站健康持续运行. 关于负载均衡介绍,可以参考:li ...

  4. Kubeadm搭建高可用(k8s)Kubernetes v1.24.0集群

    文章转载自:https://i4t.com/5451.html 背景 Kubernetes 1.24新特性 从kubelet中移除dockershim,自1.20版本被弃用之后,dockershim组 ...

  5. Nginx+keepalived 高可用双机热备(主从模式)

    环境:centos7.6 最小化安装 主:10.11.1.32 从:10.11.1.33 VIP:10.11.1.130 修改主节点主机名: hostnamectl set-hostname web_ ...

  6. 【Nginx】如何基于主从模式搭建Nginx+Keepalived双机热备环境?这是最全的一篇了!!

    写在前面 最近出版了<海量数据处理与大数据技术实战>,详情可以关注 冰河技术 微信公众号,查看<我的<海量数据处理与大数据技术实战>出版啦!>一文. 也有不少小伙伴 ...

  7. MySQL双主+keepalived实现高可用实现(热备)

    环境:centos6.7 最小化安装 192.168.100.152 master 主192.168.100.153 slave 从192.168.100.132 v_ip 浮动IP 配置ssh密码登 ...

  8. 高可用OpenStack(Queen版)集群-7.Neutron控制/网络节点集群

    参考文档: Install-guide:https://docs.openstack.org/install-guide/ OpenStack High Availability Guide:http ...

  9. 高可用OpenStack(Queen版)集群-3.高可用配置(pacemaker&haproxy)

    参考文档: Install-guide:https://docs.openstack.org/install-guide/ OpenStack High Availability Guide:http ...

随机推荐

  1. 利用sub lr,lr,#4:程序是如何进行返回的?

    1: ARM采用的是3级流水线 ARM的流水线结构为:   取指 -----> 译码 ------> 执行 ARM代码:                  PC           PC- ...

  2. 事务隔离级别与传播机制,spring+mybatis+atomikos实现分布式事务管理

    1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). 原子性(Atomicity):即事务是不可分割的最小工作单 ...

  3. js原型对象

    原型对象是什么? 在js中,每一个创建的的函数都会有一个prototype属性,这个属性指向一个对象,这个对象就是原型对象 function lla(){} console.log(lla.proto ...

  4. UEFI+GPT下安装Win10+Ubuntu16.04双系统

    安装环境 SSD+HDD双盘,Win10安装在SSD里,HDD分出来60G安装Ubuntu. 自行百度你的主板是否支持UEFI启动方式. Win10 下载Win10安装镜像.烧盘等步骤就不说了,重启后 ...

  5. pdo操纵mysql数据库

    PDO是mysql数据库操作的一个公用类了,我们不需要进行自定类就可以直接使用pdo来操作数据库了,但是在php默认配置中pdo是未开启所以我们必须先在php.ini中开启它才可以使用,下文我会讲到. ...

  6. LRU Cache java实现

    要求: get(key):如果key在cache中,则返回对应的value值,否则返回null set(key,value):如果key不在cache中,则将该(key,value)插入cache中( ...

  7. Angular2.js——主从结构

    学习这一篇的内容,还回到我们快速起步的应用上来. 主从结构,我们想要做一个英雄的列表,我们希望用户在列表中选中一个英雄,然后这个被选中的英雄出现在详情视图中.主视图是英雄列表,从视图则是被选中英雄的详 ...

  8. jquery按钮绑定特殊事件

    本文主要介绍点击一个按钮处理事件的一些特殊情况和技巧. 一.第一次点击触发一个函数,之后点击都触发另一个函数 1.小白实现 2.大神实现 代码如下: <body> <button&g ...

  9. Linux 服务器 U盘安装(避免U盘启动)

    首先下载两个文件: ·         rhel-server-6.3-i386-boot.iso    启动镜像 ·         rhel-server-6.3-i386-dvd.iso     ...

  10. 关于JS面向对象中原型和原型链以及他们之间的关系及this的详解

    一:原型和原型对象: 1.函数的原型prototype:函数才有prototype,prototype是一个对象,指向了当前构造函数的引用地址. 2.函数的原型对象__proto__:所有对象都有__ ...