Quartz是一个开源的作业调度框架,OpenSymphony的开源项目。Quartz.Net 是Quartz的C#移植版本。

一.特性:

1:支持集群,作业分组,作业远程管理。

2:自定义精细的时间触发器,使用简单,作业和触发分离。

3:数据库支持,可以寄宿Windows服务,WebSite,winform等。

二、基本概念:

Quartz框架的一些基础概念解释:

  Scheduler     作业调度器。

  IJob             作业接口,继承并实现Execute, 编写执行的具体作业逻辑。

  JobBuilder       根据设置,生成一个详细作业信息(JobDetail)。

  TriggerBuilder   根据规则,生产对应的Trigger

三、dll:

Quartz.dll

Common.Logging.dll

四、简单例子-基本使用 :

static void Main(string[] args){//从工厂中获取一个调度器实例化IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();scheduler.Start();       //开启调度器//==========例子1(简单使用)===========IJobDetail job1 = JobBuilder.Create<HelloJob>()  //创建一个作业.WithIdentity("作业名称", "作业组").Build();ITrigger trigger1 = TriggerBuilder.Create().WithIdentity("触发器名称", "触发器组").StartNow()                        //现在开始.WithSimpleSchedule(x => x         //触发时间,5秒一次。.WithIntervalInSeconds(5).RepeatForever())              //不间断重复执行.Build();scheduler.ScheduleJob(job1, trigger1);      //把作业,触发器加入调度器。//==========例子2 (执行时 作业数据传递,时间表达式使用)===========IJobDetail job2= JobBuilder.Create<DumbJob>().WithIdentity("myJob", "group1").UsingJobData("jobSays", "Hello World!").Build();ITrigger trigger2 = TriggerBuilder.Create().WithIdentity("mytrigger", "group1").StartNow().WithCronSchedule("/5 * * ? * *")    //时间表达式,5秒一次     .Build();scheduler.ScheduleJob(job2, trigger2);     //scheduler.Shutdown();         //关闭调度器。}

声明要执行的作业,实现IJob接口的execute方法:

/// <summary>/// 作业/// </summary>public class HelloJob : IJob{public void Execute(IJobExecutionContext context){Console.WriteLine("作业执行!");}}
public class DumbJob : IJob{/// <summary>///  context 可以获取当前Job的各种状态。/// </summary>/// <param name="context"></param>public void Execute(IJobExecutionContext context){JobDataMap dataMap = context.JobDetail.JobDataMap;string content = dataMap.GetString("jobSays");Console.WriteLine("作业执行,jobSays:" + content);}} 

五、Quartz.NET 的CrystalQuartz远程管理:

如果想方便的知道某个作业执行情况,需要暂停,启动等操作行为,这时候就需要个Job管理的界面,作业远程管理端,无需写任何代码,引用官方程序集,嵌入到已有的web网站。

1.相关程序集:

CrystalQuartz.Core.dll

CrystalQuartz.Web.dll

Common.Logging.dll

NVelocity.dll

Quartz.dll

RemoteSchedulerManager.dll

2.webconfig 配置:

<configuration> <crystalQuartz><provider><add property="Type" value="CrystalQuartz.Core.SchedulerProviders.RemoteSchedulerProvider, CrystalQuartz.Core" /><add property="SchedulerHost" value="tcp://127.0.0.1:556/QuartzScheduler" /> <!--TCP监听的地址--></provider></crystalQuartz>
<system.webServer><!-- Handler拦截处理了,输出作业监控页面--><handlers><add name="CrystalQuartzPanel" verb="*" path="CrystalQuartzPanel.axd" type="CrystalQuartz.Web.PagesHandler, CrystalQuartz.Web" /></handlers></system.webServer>
</configuration>

3.html页面链接设置:

<a style="font-size: 2em;" href="/CrystalQuartzPanel.axd">CrystalQuartz 管理面板</a>

4.启动自己的定时任务

5.点击链接即可进入管理界面,并看到自己的作业:

六、Quartz.NET 进阶:

1.Quartz.NET插件-ISchedulerPlugin:

在实际应用中,往往有更多的特性需求,比如记录job执行的执行历史,发邮件等。Quartz.net 自身提供了一个插件接口(ISchedulerPlugin)用来增加附加功能,看下官方定义

public interface ISchedulerPlugin{void Initialize(string pluginName, IScheduler sched);//关闭调度器void Shutdown();//插件启动void Start();}

继承接口,实现自己的插件:

public class MyPlugin : ISchedulerPlugin{public void  Initialize(string pluginName, IScheduler sched){Console.WriteLine("实例化");}public  void Start(){Console.WriteLine("启动");}public  void Shutdown(){Console.WriteLine("关闭");}}

主函数里面配置要实现的插件:

static void Main(string[] args){var properties = new NameValueCollection();//MyPlugin 自定义名称。    "命名空间.类名,程序名称"properties["quartz.plugin.MyPlugin.type"] = "QuartzDemo3.MyPlugin,QuartzDemo3";var schedulerFactory = new StdSchedulerFactory(properties);var scheduler = schedulerFactory.GetScheduler();var job = JobBuilder.Create<HelloJob>().WithIdentity("myJob", "group1").Build();var trigger = TriggerBuilder.Create().WithIdentity("mytrigger", "group1").WithCronSchedule("/2 * * ? * *").Build();scheduler.ScheduleJob(job, trigger);scheduler.Start();Thread.Sleep(6000);scheduler.Shutdown(true);Console.ReadLine();}

2.TriggerListener 和JobListener:

这2个是对触发器和job本身的行为监听器,这样更好方便跟踪Job的状态及运行情况。  通过实现ITriggerListener或IJobListener接口来实现自己的监听器:

public class MyTriggerListener : ITriggerListener{private string name;public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode){Console.WriteLine("job完成时调用");}public void TriggerFired(ITrigger trigger, IJobExecutionContext context){Console.WriteLine("job执行时调用");}public void TriggerMisfired(ITrigger trigger){Console.WriteLine("错过触发时调用(例:线程不够用的情况下)");}public bool VetoJobExecution(ITrigger trigger, IJobExecutionContext context){//Trigger触发后,job执行时调用本方法。true即否决,job后面不执行。return false;}public string Name { get { return name; } set { name = value; } }}

主函数添加:

//添加监听器到指定的triggerscheduler.ListenerManager.AddTriggerListener(myJobListener, KeyMatcher<TriggerKey>.KeyEquals(new TriggerKey("mytrigger", "group1")));添加监听器到指定分类的所有监听器。//scheduler.ListenerManager.AddTriggerListener(myJobListener, GroupMatcher<TriggerKey>.GroupEquals("myJobGroup"));添加监听器到指定分类的所有监听器。//scheduler.ListenerManager.AddTriggerListener(myJobListener, GroupMatcher<TriggerKey>.GroupEquals("myJobGroup"));添加监听器到指定的2个分组。//scheduler.ListenerManager.AddTriggerListener(myJobListener, GroupMatcher<TriggerKey>.GroupEquals("myJobGroup"), GroupMatcher<TriggerKey>.GroupEquals("myJobGroup2"));添加监听器到所有的触发器上。//scheduler.ListenerManager.AddTriggerListener(myJobListener, GroupMatcher<TriggerKey>.AnyGroup());scheduler.Start();

JobListener同理。

3.Cron表达式:

quartz.NET中的cron表达式和Linux下的很类似,比如 "/5 * * ? * * *"  这样的7位表达式,最后一位年非必选。

表达式从左到右,依此是秒、分、时、月第几天、月、周几、年。下面表格是要遵守的规范:

字段名 允许的值 允许的特殊字符
Seconds 0-59 , - * /
Minutes 0-59 , - * /
Hours 0-23 , - * /
Day of month 1-31 , - * ? / L W
Month 1-12 or JAN-DEC , - * /
Day of week 1-7 or SUN-SAT , - * ? / L #
Year 空, 1970-2099 , - * /
特殊字符 解释
, 或的意思。例:分钟位 5,10  即第5分钟或10分都触发。 
/ a/b。 a:代表起始时间,b频率时间。 例; 分钟位  3/5,  从第三分钟开始,每5分钟执行一次。
* 频率。 即每一次波动。    例;分钟位 *  即表示每分钟 
- 区间。  例: 分钟位   5-10 即5到10分期间。 
? 任意值 。   即每一次波动。只能用在DayofMonth和DayofWeek,二者冲突。指定一个另一个一个要用?
L 表示最后。 只能用在DayofMonth和DayofWeek,4L即最后一个星期三
W 工作日。  表示最后。 只能用在DayofWeek
# 4#2。 只能用DayofMonth。 某月的第二个星期三  

实例介绍

”0 0 10,14,16 * * ?"    每天10点,14点,16点 触发。

"0 0/5 14,18 * * ?"    每天14点或18点中,每5分钟触发 。

"0 4/15 14-18 * * ?"       每天14点到18点期间,  从第四分钟触发,每15分钟一次。

"0 15 10 ? * 6L"        每月的最后一个星期五上午10:15触发。

4.Quartz.NET线程池:

线程池数量设置:

properties["quartz.threadPool.threadCount"] = "5";//是指同一时间,调度器能执行Job的最大数量。

这个线程池的设置,是指同时间,调度器能执行Job的最大数量。

quartz是用每个线程跑一个job。上面的设置可以解释是job并发时能执行5个job,剩下的job如果触发时间恰好到了,当前job会进入暂停状态,直到有可用的线程。

如果在指定的时间范围依旧没有可用线程,会触发misfired时间。

quartz 提供了IThreadPool接口,也可以用自定义线程池来实现。

配置如下:

properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz"; 

一般来说作业调度很少并发触发大量job,如果有上百个JOB,可在服务器承受范围内适量增加线程数量

七、Quartz.NET持久化-JobStore:

作业一旦被调度,调度器需要记住并且跟踪作业和它们的执行次数。如果你的作业是30分钟后或每30秒调用,这不是很有用。事实上,作业执行需要非常
准确和即时调用在被调度作业上的Execute()方法。Quartz.NET通过一个称之为作业存储(JobStore)的概念来做作业存储和管理。

Quartz.NET提供两种基本作业存储类型。第一种类型叫做RAMJobStore,它利用通常的内存来持久化调度程序信息。这种作业存储类型最容易配置、构造和运行。Quartz.net缺省使用的就是RAMJobStore。对许多应用来说,这种作业存储已经足够了。

然而,因为调度程序信息是存储在被分配在内存里面,所以,当应用程序停止运行时,所有调度信息将被丢失。如果你需要在重新启动之间持久化调度信息,则将需要第二种类型的作业存储。为了修正这个问题,Quartz.NET 提供了 AdoJobStore。顾名思义,作业仓库通过
ADO.NET把所有数据放在数据库中。数据持久性的代价就是性能降低和复杂性的提高。它将所有的数据通过ADO.NET保存到数据库可中。它的配置要比RAMJobStore稍微复杂,同时速度也没有那么快。但是性能的缺陷不是非常差,尤其是如果你在数据库表的主键上建立索引。

AdoJobStore几乎可以在任何数据库上工作,它广泛地使用Oracle, MySQL, MS SQLServer2000,HSQLDB, PostreSQL 以及 DB2。要使用AdoJobStore,首先必须创建一套Quartz使用的数据库表,可以在Quartz的database\tables找到创建库表的SQL脚本。如果没有找到你的

数据库类型的脚本,那么找到一个已有的,修改成为你数据库所需要的。需要注意的一件事情就是所有Quartz库表名都以QRTZ_作为前缀(例如:表"QRTZ_TRIGGERS",及"QRTZ_JOB_DETAIL")。实际上,可以你可以将前缀设置为任何你想要的前缀,只要你告诉AdoJobStore

那个前缀是什么即可(在你的Quartz属性文件中配置)。对于一个数据库中使用多个scheduler实例,那么配置不同的前缀可以创建多套库表,十分有用。(下载SQL脚本)。

配置:

            properties["quartz.scheduler.instanceName"] = "TestScheduler";properties["quartz.scheduler.instanceId"] = "instance_one";properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";properties["quartz.threadPool.threadCount"] = "5";properties["quartz.threadPool.threadPriority"] = "Normal";properties["quartz.jobStore.misfireThreshold"] = "60000";properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz";properties["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz";properties["quartz.jobStore.useProperties"] = "false";properties["quartz.jobStore.dataSource"] = "default";properties["quartz.jobStore.tablePrefix"] = "QRTZ_";properties["quartz.jobStore.clustered"] = "true";// if running MS SQL Server we need thisproperties["quartz.jobStore.selectWithLockSQL"] = "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = @lockName";properties["quartz.dataSource.default.connectionString"] = @"Server=V-LOZHU02;Database=quartz;Trusted_Connection=True;";properties["quartz.dataSource.default.provider"] = "SqlServer-20";

持久化后,job只有添加一次了(数据库已经有了),所以不能再执行端写添加job的行为,可以在执行job前先清空数据库中的job防止重复添加报异常:

       public virtual void CleanUp(IScheduler inScheduler){_log.Warn("***** Deleting existing jobs/triggers *****");// unschedule jobsstring[] groups = inScheduler.TriggerGroupNames;for (int i = 0; i < groups.Length; i++){String[] names = inScheduler.GetTriggerNames(groups[i]);for (int j = 0; j < names.Length; j++)inScheduler.UnscheduleJob(names[j], groups[i]);}// delete jobsgroups = inScheduler.JobGroupNames;for (int i = 0; i < groups.Length; i++){String[] names = inScheduler.GetJobNames(groups[i]);for (int j = 0; j < names.Length; j++)inScheduler.DeleteJob(names[j], groups[i]);}}

先从初始化 SchedulerFactory 和Scheduler开始。然后,不再需要初始化作业和触发器,而是要获取触发器群组名称列表,之后对于每个群组名称,获取触发器名称列表。请注意,每个现有的作业都应当用
Scheduler. RescheduleJob ()方法重新调度。仅仅重新初始化在先前的应用程序运行时终止的作业,不会正确地装载触发器的属性。

8. 将Quartz.NET 服务创建到window services中:https://github.com/zhulongxi2015/Quartz.NETProject/tree/master

8.1.首先创建Windows服务程序(windows service):QuartzArchitecture.Service

引用程序集:Quartz.dll, log4net.dll,Common.Logging.Log4Net.dll(不能少,没有它的话在创建服务的时候回有1053错误码),Common.Logging.dll

此时自动生成一个ProjectInstaller.cs服务组件类,将serviceInstaller1的StartType设为Automatic,serviceProcessInstaller1的Account设置为LocalSystem.

新建一个自己的服务组件类:MyQuartzService1.cs,继承自ServiceBase类,在里面分别重写OnStart,OnStop,OnPause,OnContinue方法。在构造函数中实例化scheduler..

在app.confg中配置log4net ,common, quartz节点:

 <configSections><section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"/><section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/><sectionGroup name="common"><section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/></sectionGroup></configSections>
 <common><logging><factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4net"><arg key="configType" value="INLINE"/><arg key="level" value="ALL" /><arg key="showLogName" value="true" /><arg key="showDataTime" value="true" /><arg key="dateTimeFormat" value="yyyy/MM/dd HH:mm:ss:fff" /></factoryAdapter></logging></common><log4net><appender name="InfoFileAppender" type="log4net.Appender.RollingFileAppender"><file value="log/" /><appendToFile value="true" /><param name="DatePattern" value="yyyyMMdd".txt"" /><rollingStyle value="Date" /><maxSizeRollBackups value="100" /><maximumFileSize value="1024KB" /><staticLogFileName value="false" /><Encoding value="UTF-8" /><filter type="log4net.Filter.LevelRangeFilter"><param name="LevelMin" value="INFO" /><param name="LevelMax" value="INFO" /></filter><layout type="log4net.Layout.PatternLayout"><conversionPattern value="%date %-5level %logger  - %message%newline" /></layout></appender><appender name="ErrorFileAppender" type="log4net.Appender.RollingFileAppender"><file value="log/error.txt" /><appendToFile value="true" /><rollingStyle value="Size" /><maxSizeRollBackups value="100" /><maximumFileSize value="10240KB" /><staticLogFileName value="true" /><Encoding value="UTF-8" /><filter type="log4net.Filter.LevelRangeFilter"><param name="LevelMin" value="WARN" /><param name="LevelMax" value="FATAL" /></filter><layout type="log4net.Layout.PatternLayout"><conversionPattern value="%date %-5level %logger - %message%newline" /></layout></appender><root><level value="INFO" /><appender-ref ref="InfoFileAppender" /><appender-ref ref="ErrorFileAppender" /></root></log4net><quartz><add key="quartz.scheduler.instanceName" value="ServerScheduler" /><add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz" /><add key="quartz.threadPool.threadCount" value="10" /><add key="quartz.threadPool.threadPriority" value="2" /><add key="quartz.jobStore.misfireThreshold" value="60000" /><add key="quartz.jobStore.type" value="Quartz.Simpl.RAMJobStore, Quartz" /></quartz>

8.2.创建Job类库:MyQuartzArchitecture.Jobs

在里面添加自己的job:(实现IJob接口)

8.3.创建Runner类库,表示使用哪种存储(adostore\simple):QuartzRunner

8.4 编译服务QuartzRunner,将bin中的文件拷到磁盘下面,(如d:\service),

通过cmd: sc create servicename binpath=d:\svervice\QuartzArchitecture.Service.exe 创建服务。

net start servicename 启用服务

net stop servicename 停止服务

source code: https://github.com/zhulongxi2015/Quartz.NETSource

demo: https://github.com/zhulongxi2015/Quart.NETSimpleDemo

http://www.cnblogs.com/lzrabbit/archive/2012/04/14/2446942.html

.NET作业调度 Quartz.NET相关推荐

  1. C#作业调度Quartz简单使用

    首先,作业调度Quartz的定义是: Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.ne ...

  2. ABP后台服务之作业调度Quartz.NET

    一.简介 Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中.它提供了巨大的灵活 ...

  3. java quartz job_用 Quartz 进行作业调度

    用 Quartz 进行作业调度 Quartz API 采用多面方式在 Java 应用程序中进行任务调度 Michael Lipton 和 Soobaek Jang 2006 年 12 月 28 日发布 ...

  4. 企业应用中的作业调度

    第一章.  企业应用中的作业调度     ·什么是作业调度     ·作业调度为什么说是重要的     ·企业应用中的作业调度     ·非企业应用中的作业调度     ·作业调度与工作流     · ...

  5. hibernate oracle 读写分离_ASP.NET CORE 国产最火前后端完全分离框架BCVP

    BCVP(Blog.Core&Vue Project)是.NET界开箱即用的企业级前后端分离[ .NET Core3.1 Api + Vue 2.x + RBAC]权限框架,由国内微软MVP& ...

  6. 回首2015年小文codeRoad

    1.Java基础知识(排序.算法.设计模式.I/O.多线程.Swing等.面向对象编程思想) 2.前端框架:jqueryUI.EasyUI.BootStrap.Anglurjs.EXT.Html5.C ...

  7. Java学习路线从入门到入土

    Java学习路线从入门到入土 Java学习路线从入门到入土 Java学习路线从入门到入土 简介 Java基础课程 第一阶段 第一部分:Java开发介绍 第二部分:Java数组 第三部分:Java面向对 ...

  8. Net作业调度(一) -Quartz.Net入门

    背景 很多时候,项目需要在不同时刻,执行一个或很多个不同的作业. Windows执行计划这时并不能很好的满足需求了,迫切需要一个更为强大,方便管理,集群部署的作业调度框架. 介绍 Quartz一个开源 ...

  9. Quartz作业调度框架

    Quartz 是一个开源的作业调度框架,它完全由 Java 写成,并设计用于 J2SE 和 J2EE 应用中.它提供了巨大的灵活性而不牺牲简单性.你能够用它来为执行一个作业而创建简单的或复杂的调度.本 ...

最新文章

  1. Alteral Max 10 FPGA 优点
  2. 无锡计算机硬件培训,无锡锡山办公软件电脑基础培训随到随学 学会为止
  3. 【转】.NET试题总结二
  4. pdfwin10闪退_win10系统打开文件夹闪退的解决方法
  5. C# 中 ? 和 ??
  6. 极客大学产品经理训练营:数据分析 第八章作业
  7. OpenCV 二值化
  8. 常用网络特殊符号大全(含彩色表情符号)
  9. Linux源码安装pgadmin4,pgAdmin4 - 搞定安装部署
  10. RNA甲基化修饰m6A检测热门技术—MeRIP-seq
  11. 仿微博视频边下边播之滑动 TableView 自动播放
  12. pythonshell窗口是什么_使用IDLE的Python shell窗口实例详解
  13. adb shell循环命令_android adb实用命令小结
  14. 系统分区减小_每日一练,防排烟系统,6.1
  15. 盘点10个堪称神器,却不为人所知的小众软件
  16. 达梦数据库 ,无效的列名, org.springframework.dao.DataIntegrityViolationException: Hibernate-related JDBC operat
  17. mysql5.6版本 百度百科_作为DBA不得不掌握的一个mysql兼容参数-show_compatibility_56-建站-站长头条...
  18. 无人车采用纯跟踪算法跟随离线路径(ROS,C++实现)第一部分
  19. IDEA的Project与Structure依赖jar包的方式
  20. 运用Acronis True Image恢复系统

热门文章

  1. java进程在经过压力测试后,系统内存占用比居高不下
  2. ZBrush的一些快捷键和基本操作
  3. 基于java+springboot+mybatis+vue+elementui的口腔牙医诊所系统
  4. Github使用(3)-Git的其他用法
  5. 使用Java的JDK自带工具对中文汉字进行转码
  6. GPT-4 被开源,OpenAI:不撤下就告你;推特将发单篇付费,马斯克:双赢;中国棋手首夺「世界棋王」,奖金 830 万
  7. hduOJ(2007-2010)
  8. 微信公众号自动回复 - 自定义设置
  9. 借助trinamic精确控制医疗设备
  10. 学习的三部曲:WHAT、HOW、WHY