使用Quartz.NET进行任务调度管理

1、Quartz.NET 介绍

  Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,支持cron-like表达式等等。  
      你曾经需要应用执行一个任务吗?这个任务每天或每周星期二晚上11:30,或许仅仅每个月的最后一天执行。一个自动执行而无须干预的任务在执行过程中如果发生一个严重错误,应用能够知到其执行失败并尝试重新执行吗?你和你的团队是用.NET编程吗?如果这些问题中任何一个你回答是,那么你应该使用Quartz.NET调度器。 Quartz.NET允许开发人员根据时间间隔(或天)来调度作业。它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联。整合了 Quartz.NET的应用程序可以重用来自不同事件的作业,还可以为一个事件组合多个作业。

2、Quartz体系结构(参考:http://www.blogjava.net/baoyaer/articles/155645.html

Quartz对任务调度的领域问题进行了高度的抽象,提出了调度器、任务和触发器这3个核心的概念,并在org.quartz通过接口和类对重要的这些核心概念进行描述:

●Job:是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中;

●JobDetail:Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job。因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息,JobDetail承担了这一角色。

通过该类的构造函数可以更具体地了解它的功用:JobDetail(java.lang.String name, java.lang.String group, java.lang.Class jobClass),该构造函数要求指定Job的实现类,以及任务在Scheduler中的组名和Job名称;

●Trigger:是一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。当仅需触发一次或者以固定时间间隔周期执行,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案:如每早晨9:00执行,周一、周三、周五下午5:00执行等;

●Calendar:org.quartz.Calendar和java.util.Calendar不同,它是一些日历特定时间点的集合(可以简单地将org.quartz.Calendar看作java.util.Calendar的集合——java.util.Calendar代表一个日历时间点,无特殊说明后面的Calendar即指org.quartz.Calendar)。一个Trigger可以和多个Calendar关联,以便排除或包含某些时间点。

  假设,我们安排每周星期一早上10:00执行任务,但是如果碰到法定的节日,任务则不执行,这时就需要在Trigger触发机制的基础上使用Calendar进行定点排除。针对不同时间段类型,Quartz在org.quartz.impl.calendar包下提供了若干个Calendar的实现类,如AnnualCalendar、MonthlyCalendar、WeeklyCalendar分别针对每年、每月和每周进行定义;

●Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。

  Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。SchedulerContext内部通过一个Map,以键值对的方式维护这些上下文数据,SchedulerContext为保存和获取数据提供了多个put()和getXxx()的方法。可以通过Scheduler# getContext()获取对应的SchedulerContext实例;

●ThreadPool:Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。

  Job有一个StatefulJob子接口,代表有状态的任务,该接口是一个没有方法的标签接口,其目的是让Quartz知道任务的类型,以便采用不同的执行方案。无状态任务在执行时拥有自己的JobDataMap拷贝,对JobDataMap的更改不会影响下次的执行。而有状态任务共享共享同一个JobDataMap实例,每次任务执行对JobDataMap所做的更改会保存下来,后面的执行可以看到这个更改,也即每次执行任务后都会对后面的执行发生影响。正因为这个原因,无状态的Job可以并发执行,而有状态的StatefulJob不能并发执行,这意味着如果前次的StatefulJob还没有执行完毕,下一次的任务将阻塞等待,直到前次任务执行完毕。有状态任务比无状态任务需要考虑更多的因素,程序往往拥有更高的复杂度,因此除非必要,应该尽量使用无状态的Job。如果Quartz使用了数据库持久化任务调度信息,无状态的JobDataMap仅会在Scheduler注册任务时保持一次,而有状态任务对应的JobDataMap在每次执行任务后都会进行保存。

  Trigger自身也可以拥有一个JobDataMap,其关联的Job可以通过JobExecutionContext.getTrigger().getJobDataMap()获取Trigger中的JobDataMap。不管是有状态还是无状态的任务,在任务执行期间对Trigger的JobDataMap所做的更改都不会进行持久,也即不会对下次的执行产生影响。

  Quartz拥有完善的事件和监听体系,大部分组件都拥有事件,如任务执行前事件、任务执行后事件、触发器触发前事件、触发后事件、调度器开始事件、关闭事件等等,可以注册相应的监听器处理感兴趣的事件。

  一个Scheduler可以拥有多个Triger组和多个JobDetail组,注册Trigger和JobDetail时,如果不显式指定所属的组,Scheduler将放入到默认组中,默认组的组名为Scheduler.DEFAULT_GROUP。组名和名称组成了对象的全名,同一类型对象的全名不能相同。Scheduler本身就是一个容器,它维护着Quartz的各种组件并实施调度的规则。Scheduler还拥有一个线程池,线程池为任务提供执行线程——这比执行任务时简单地创建一个新线程要拥有更高的效率,同时通过共享节约资源的占用。通过线程池组件的支持,对于繁忙度高、压力大的任务调度,Quartz将可以提供良好的伸缩性。

3、配置Quartz.NET

  Quartz.NET使用前需要进行配置,需要配置的项主要包括quartz.scheduler.instanceName、quartz.threadPool.type、quartz.threadPool.threadCount、quartz.jobStore.misfireThreshold等信息。Quartz.NET的日志使用的是Common.Logging,能够将信息输出到控制台,我这里使用日志配置是Common.Logging和log4net结合的方式(参考:http://www.cnblogs.com/chen-whutgis/p/4129271.html)。

<?xml version="1.0"?>
<configuration>

  <configSections>
    <section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
    <sectionGroup name="common">
      <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
    </sectionGroup>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>

  <common>
    <logging>
      <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter,Common.Logging.Log4Net1210">
        <arg key="configType" value="INLINE" />
      </factoryAdapter>
    </logging>
  </common>

  <log4net>
    <root>
      <appender-ref ref="RollingFileAppender" />
    </root>

    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger %ndc - %message%newline" />
      </layout>
    </appender>

    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <param name="File" value="..\\Data\\Log\\Log.txt" />
      <param name="AppendToFile" value="true" />
      <param name="MaxSizeRollBackups" value="10" />
      <param name="MaximumFileSize" value="5MB" />
      <param name="RollingStyle" value="Size" />
      <param name="StaticLogFileName" value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%n[时间]:%d%n[级别]:%p%n[内容]:%m%n" />
      </layout>
    </appender>

  </log4net>

  <quartz>
    <add key="quartz.scheduler.instanceName" value="ExampleDefaultQuartzScheduler"/>

    <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"/>

    <!-- sample configuration based db provider -->
    <add key="quartz.dbprovider.customProvider.productName" value="Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0"/>
    <add key="quartz.dbprovider.customProvider.assemblyName" value="System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <add key="quartz.dbprovider.customProvider.connectionType" value="System.Data.SqlClient.SqlConnection, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <add key="quartz.dbprovider.customProvider.commandType" value="System.Data.SqlClient.SqlCommand, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <add key="quartz.dbprovider.customProvider.parameterType" value="System.Data.SqlClient.SqlParameter, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <add key="quartz.dbprovider.customProvider.commandBuilderType" value="System.Data.SqlClient.SqlCommandBuilder, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <add key="quartz.dbprovider.customProvider.parameterDbType" value="System.Data.SqlDbType, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <add key="quartz.dbprovider.customProvider.parameterDbTypePropertyName" value="SqlDbType" />
    <add key="quartz.dbprovider.customProvider.parameterNamePrefix" value="@" />
    <add key="quartz.dbprovider.customProvider.exceptionType" value="System.Data.SqlClient.SqlException, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <add key="quartz.dbprovider.customProvider.useParameterNamePrefixInParameterCollection" value="true" />
    <add key="quartz.dbprovider.customProvider.bindByName" value="true" />
    <add key="quartz.dbprovider.customProvider.dbBinaryTypeName" value="Image" />

  </quartz>

</configuration>

 4、使用Quartz.NET

  TestJob继承IJob接口

 1 using System;
 2
 3 using Quartz;
 4
 5 namespace QuartzTest
 6 {
 7     public class TestJob:IJob
 8     {
 9         public void Execute(IJobExecutionContext context)
10         {
11              Console.WriteLine("Test Job Excute");
12         }
13     }
14
15 }
16      

  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Quartz;

namespace QuartzTest
{
    class Program
    {
        static void Main(string[] args)
        {
            ISchedulerFactory sf = new StdSchedulerFactory();
            IScheduler sched = sf.GetScheduler();

            ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create()
                                                  .WithIdentity("trigger1", "group1")
                                                  .WithCronSchedule("0 15 10 ? * MON")//每周一的10:15分运行。
                                                  .Build();
            IJobDetail job = JobBuilder.Create<TestJob>()
                       .WithIdentity("TestJob", "group1")
                       .Build();
            DateTimeOffset ft = sched.ScheduleJob(job, trigger);

        sched.Start();
        }
    }
}
时间: 2024-10-17 18:26:12

使用Quartz.NET进行任务调度管理的相关文章

[更新] 基于Quartz.NET 的任务调度管理工具

更新列表: 任务参数可视化. 立即中断正在执行的任务. 每个任务独立的应用程序域 上一版参见: 基于Quqrtz.NET 做的任务调度管理工具 界面具体变化如下: 任务参数可视化 如上图所示, 在管理任务的界面上就可以知道这个任务需哪些参数/类型 及 参数的说明. 实现方式, 在 Job 上添加 特性 :  ParameterTypeAttribute 1 namespace JobA { 2 [ParameterType(typeof(Parameter))] 3 public class J

quartz 定时任务调度管理器

本项目使用的是spring-quartz 以下配置可以开启多个已知定时任务 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:ta

Spring整合Quartz实现定时任务调度

一. 核心类 1. Job: 表示一个工作, 具体的业务处理都在这里. 2. JobDetail: 表示一个具体的可执行的调度程序. 3. Trigger: 用于调度参数的配置(什么时候去调用Job). 4. Scheduler: 表示一个调度容器, 容器中有一个线程池, 用来并行调度执行每个作业, 一个调度容器中可以注册多个JobDetail和Trigger. 二. 整合spring 1. 代码结构图: 2. applicationContext.xml <?xml version="1

项目ITP(六) spring4.0 整合 Quartz 实现动态任务调度

前言 系列文章:[传送门] 项目需求: http://www.cnblogs.com/Alandre/p/3733249.html 上一博客写的是基本调度,后来这只能用于,像每天定个时间 进行数据库备份.但是,远远不能在上次的需求上实现.所以需要实现spring4.0 整合 Quartz 实现动态任务调度. 正文 spring4.0 整合 Quartz 实现任务调度.这真是期末项目的最后一篇,剩下到暑假吧.  Quartz 介绍 Quartz is a full-featured, open s

基于 Quartz 开发企业级任务调度应用--转

Quartz 基本概念及原理 Quartz Scheduler 开源框架 Quartz 是 OpenSymphony 开源组织在任务调度领域的一个开源项目,完全基于 Java 实现.该项目于 2009 年被 Terracotta 收购,目前是 Terracotta 旗下的一个项目.读者可以到 http://www.quartz-scheduler.org/站点下载 Quartz 的发布版本及其源代码.笔者在产品开发中使用的是版本 1.8.4,因此本文内容基于该版本.本文不仅介绍如何应用 Quar

Hosted Services+Quartz实现定时任务调度

背景 之前.net core使用quartz.net时,总感觉非常变扭,百度和谷歌了N久都没解决以下问题,造成代码丑陋,非常不优雅: 1.项目启动时,要立刻恢复执行quartz.net中的任务 2.quartz.net中的Job任务无法使用ioc注入,要额外写一套 直到最近看到这篇文章.Net Core小技巧 - Hosted Services + Quartz实现定时任务调度,终于解决了我的问题,特此记录一下 前后代码对比 Program.cs 前 查看详细内容 public class Pr

基于Quqrtz.NET 做的任务调度管理工具

国庆前,需求让我看了一下任务调度的数据表设计.和之前一样,有100多个字段,p1 ~ p100, 我说这是干嘛啊!按这写,写死去了! 然后在网上搜了一下开源的任务调度,第一个中意的就是 Quartz.NET,10.1 出来和老领导聚会,老领导说了另外一个东西:Zookeeper, 刚搜了一下,也有.NET的版本. 先入为主,Zookeeper 我就不深入了,整个10.1 在家基本除了看电影就是看 Quartz 了. Quartz.net 提供了 Remoting 方式,Remoting 我08年

基于 Quartz 开发企业级任务调度应用

原文地址:https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/ Quartz 是 OpenSymphony 开源组织在任务调度领域的一个开源项目,完全基于 Java 实现.作为一个优秀的开源调度框架,Quartz 具有功能强大,应用灵活,易于集成的特点.本文剖析了 Quartz 框架内部的基本实现原理,通过一些具体实例描述了应用 Quartz 开发应用程序的基本方法,并对企业应用中常见的问题及解决方案进行了讨论. Quart

【淘淘】Quartz作业存储与管理

一.Quartz作业管理和存储方式简介: 作业一旦被调度,调度器需要记住并且跟踪作业和它们的执行次数.如果你的作业是30分钟后或每30秒调用,这不是很有用.事实上,作业执行需要非常准确和即时调用在被调度作业上的execute()方法.Quartz通过一个称之为作业存储(JobStore)的概念来做作业存储和管理. Quartz提供两种基本作业存储类型.第一种类型叫做RAMJobStore,它利用通常的内存来持久化调度程序信息.这种作业存储类型最容易配置.构造和运行.对许多应用来说,这种作业存储已