Quartz+TopShelf实现Windows服务作业调度

 

  Quartz:首先我贴出来了两段代码(下方),可以看出,首先会根据配置文件(quartz.config),包装出一个Quartz.Core.QuartzScheduler

instance,这是一个调度器,调度各个任务项(Jobs)的执行。这个调度器可以被Start、被Shutdown、被PauseAll、被ResumeAll,这对应

了windows服务的开启、停止、暂停、恢复。当启动服务,我就调用调度器的Start(),停止服务我就调用调度器的Shutdown()方法。

namespace QTDemo
{
public class ServiceRunner : ServiceControl, ServiceSuspend
{
private readonly IScheduler scheduler; public ServiceRunner()
{
scheduler = StdSchedulerFactory.GetDefaultScheduler();
} public bool Start(HostControl hostControl)
{
scheduler.Start();
return true;
}
// 摘要:
// An implementation of Quartz.ISchedulerFactory that does all of it's work
// of creating a Quartz.Core.QuartzScheduler instance based on the contents
// of a properties file.
public class StdSchedulerFactory : ISchedulerFactory
{
public const string AutoGenerateInstanceId = "AUTO";
public const string ConfigurationSectionName = "quartz";
public const string DefaultInstanceId = "NON_CLUSTERED";
public const string PropertiesFile = "quartz.config";

  那TopShelf又扮演了什么样的角色呢

  这是一个宿主服务的框架。和ServiceBase、ServiceInstaller那一套的目的一样,都是用来创建Windows服务的。

项目示例

1、新建项目控制台应用程序‘QTDemo’

2、从NuGet安装‘Quartz’,‘Topshelf’,‘Topshelf.Log4Net’

1 <?xml version="1.0" encoding="utf-8"?>
2 <packages>
3 <package id="Common.Logging" version="3.3.1" targetFramework="net45" />
4 <package id="Common.Logging.Core" version="3.3.1" targetFramework="net45" />
5 <package id="log4net" version="2.0.5" targetFramework="net45" />
6 <package id="Quartz" version="2.3.3" targetFramework="net45" />
7 <package id="Topshelf" version="3.3.1" targetFramework="net45" />
8 <package id="Topshelf.Log4Net" version="3.3.1" targetFramework="net45" />
9 </packages>

3、定义一个Job(一个任务项),继承Quartz.IJob

 1 using Quartz;
2 namespace QTDemo.QuartzJobs
3 {
4 public sealed class TestJob : IJob
5 {
6 public void Execute(IJobExecutionContext context)
7 {
8 CommonHelper.AppLogger.InfoFormat("TestJob测试");
9
10 }
11 }
12 }
13

4、配置(新建)quartz.config、quartz_jobs.xml

quartz.config可直接使用,不用修改

 1 # You can configure your scheduler in either <quartz> configuration section
2 # or in quartz properties file
3 # Configuration section has precedence
4
5 quartz.scheduler.instanceName = QuartzTest
6
7 # configure thread pool info
8 quartz.threadPool.type = Quartz.Simpl.SimpleThreadPool, Quartz
9 quartz.threadPool.threadCount = 10
10 quartz.threadPool.threadPriority = Normal
11
12 # job initialization plugin handles our xml reading, without it defaults are used
13 quartz.plugin.xml.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz
14 quartz.plugin.xml.fileNames = ~/quartz_jobs.xml
15
16 # export this server to remoting context
17 #quartz.scheduler.exporter.type = Quartz.Simpl.RemotingSchedulerExporter, Quartz
18 #quartz.scheduler.exporter.port = 555
19 #quartz.scheduler.exporter.bindName = QuartzScheduler
20 #quartz.scheduler.exporter.channelType = tcp
21 #quartz.scheduler.exporter.channelName = httpQuartz

quartz_jobs.xml根据实际的Job项修改

 1 <?xml version="1.0" encoding="utf-8" ?>
2 <!-- This file contains job definitions in schema version 2.0 format -->
3
4 <job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">
5
6 <processing-directives>
7 <overwrite-existing-data>true</overwrite-existing-data>
8 </processing-directives>
9
10 <schedule>
11
12 <!--TestJob测试 任务配置 -->
13 <job>
14 <name>TestJob</name>
15 <group>Test</group>
16 <description>TestJob测试</description>
17 <job-type>QTDemo.QuartzJobs.TestJob,QTDemo</job-type>
18 <durable>true</durable>
19 <recover>false</recover>
20 </job>
21 <trigger>
22 <cron>
23 <name>TestJobTrigger</name>
24 <group>Test</group>
25 <job-name>TestJob</job-name>
26 <job-group>Test</job-group>
27 <!-- 从start-time起,每5s执行一次IJob.Execute -->
28 <start-time>2012-01-22T00:00:00+08:00</start-time>
29 <cron-expression>0/5 * * * * ?</cron-expression>
30 </cron>
31 </trigger>
32
33 </schedule>
34 </job-scheduling-data>

5、创建服务

入口:

 1 using System;
2 using System.IO;
3 using Topshelf;
4
5 namespace QTDemo
6 {
7 class Program
8 {
9 static void Main(string[] args)
10 {
11 log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "log4net.config"));
12
16 HostFactory.Run(x =>
17 {
18 x.UseLog4Net();
19
20 x.Service<ServiceRunner>();
21
22 x.RunAsLocalSystem();
23
24 x.SetDescription("Quartz+TopShelf实现Windows服务作业调度的一个示例Demo");
25 x.SetDisplayName("QuartzTopShelfDemo服务");
26 x.SetServiceName("QuartzTopShelfDemoService");
27
28 x.EnablePauseAndContinue();
29
30 });
31 }
32 }
33 }

ServiceRunner.cs

 1 using Quartz;
2 using Quartz.Impl;
3 using Topshelf;
4
5 namespace QTDemo
6 {
7 public class ServiceRunner : ServiceControl, ServiceSuspend
8 {
9 private readonly IScheduler scheduler;
10
11 public ServiceRunner()
12 {
13 scheduler = StdSchedulerFactory.GetDefaultScheduler();
14 }
15
16 public bool Start(HostControl hostControl)
17 {
18 scheduler.Start();
19 return true;
20 }
21
22 public bool Stop(HostControl hostControl)
23 {
24 scheduler.Shutdown(false);
25 return true;
26 }
27
28 public bool Continue(HostControl hostControl)
29 {
30 scheduler.ResumeAll();
31 return true;
32 }
33
34 public bool Pause(HostControl hostControl)
35 {
36 scheduler.PauseAll();
37 return true;
38 }
39
40 }
41 }

log4net配置文件,可直接使用

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>

<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<!--日志路径-->
<param name= "File" value= "Log\"/>
<!--是否是向文件中追加日志-->
<param name= "AppendToFile" value= "true"/>
<!--log保留天数-->
<param name= "MaxSizeRollBackups" value= "10"/>
<!--日志文件名是否是固定不变的-->
<param name= "StaticLogFileName" value= "false"/>
<!--日志文件名格式为:2008-08-31.log-->
<param name= "DatePattern" value= "yyyy-MM-dd&quot;.read.log&quot;"/>
<!--日志根据日期滚动-->
<param name= "RollingStyle" value= "Date"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%date{HH:mm:ss,fff} %-5p-%m%n" />
</layout>
</appender>

<!-- 控制台前台显示日志 -->
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="ERROR" />
<foreColor value="Red, HighIntensity" />
</mapping>
<mapping>
<level value="Info" />
<foreColor value="Green" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%n%date{HH:mm:ss,fff} [%-5level] %m" />
</layout>

<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="Info" />
<param name="LevelMax" value="Fatal" />
</filter>
</appender>

<root>
<!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
<level value="all" />
<appender-ref ref="ColoredConsoleAppender"/>
<appender-ref ref="RollingLogFileAppender"/>
</root>

</log4net>
</configuration>

 1 <?xml version="1.0" encoding="utf-8" ?>
2 <configuration>
3 <configSections>
4 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
5 </configSections>
6
7 <log4net>
8 <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
9 <!--日志路径-->
10 <param name= "File" value= "Log\"/>
11 <!--是否是向文件中追加日志-->
12 <param name= "AppendToFile" value= "true"/>
13 <!--log保留天数-->
14 <param name= "MaxSizeRollBackups" value= "10"/>
15 <!--日志文件名是否是固定不变的-->
16 <param name= "StaticLogFileName" value= "false"/>
17 <!--日志文件名格式为:2008-08-31.log-->
18 <param name= "DatePattern" value= "yyyy-MM-dd&quot;.read.log&quot;"/>
19 <!--日志根据日期滚动-->
20 <param name= "RollingStyle" value= "Date"/>
21 <layout type="log4net.Layout.PatternLayout">
22 <param name="ConversionPattern" value="%date{HH:mm:ss,fff} %-5p-%m%n" />
23 </layout>
24 </appender>
25
26 <!-- 控制台前台显示日志 -->
27 <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
28 <mapping>
29 <level value="ERROR" />
30 <foreColor value="Red, HighIntensity" />
31 </mapping>
32 <mapping>
33 <level value="Info" />
34 <foreColor value="Green" />
35 </mapping>
36 <layout type="log4net.Layout.PatternLayout">
37 <conversionPattern value="%n%date{HH:mm:ss,fff} [%-5level] %m" />
38 </layout>
39
40 <filter type="log4net.Filter.LevelRangeFilter">
41 <param name="LevelMin" value="Info" />
42 <param name="LevelMax" value="Fatal" />
43 </filter>
44 </appender>
45
46 <root>
47 <!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
48 <level value="all" />
49 <appender-ref ref="ColoredConsoleAppender"/>
50 <appender-ref ref="RollingLogFileAppender"/>
51 </root>
52
53 </log4net>
54 </configuration>

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>

<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<!--日志路径-->
<param name= "File" value= "Log\"/>
<!--是否是向文件中追加日志-->
<param name= "AppendToFile" value= "true"/>
<!--log保留天数-->
<param name= "MaxSizeRollBackups" value= "10"/>
<!--日志文件名是否是固定不变的-->
<param name= "StaticLogFileName" value= "false"/>
<!--日志文件名格式为:2008-08-31.log-->
<param name= "DatePattern" value= "yyyy-MM-dd&quot;.read.log&quot;"/>
<!--日志根据日期滚动-->
<param name= "RollingStyle" value= "Date"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%date{HH:mm:ss,fff} %-5p-%m%n" />
</layout>
</appender>

<!-- 控制台前台显示日志 -->
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="ERROR" />
<foreColor value="Red, HighIntensity" />
</mapping>
<mapping>
<level value="Info" />
<foreColor value="Green" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%n%date{HH:mm:ss,fff} [%-5level] %m" />
</layout>

<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="Info" />
<param name="LevelMax" value="Fatal" />
</filter>
</appender>

<root>
<!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
<level value="all" />
<appender-ref ref="ColoredConsoleAppender"/>
<appender-ref ref="RollingLogFileAppender"/>
</root>

</log4net>
</configuration>

6、quartz.config、quartz_jobs.xml、log4net.config都设置成‘始终复制’

7、直接F5,调试,发现TestJob每5s执行一次

8、安装成Windows服务

用Release编一个版本

然后用命令行安装服务

服务面板里可以找到此服务

启动之,查看日志文件,服务运行正常

23:23:52,171 INFO -Configuration Result:
[Success] Name QuartzTopShelfDemoService
[Success] DisplayName QuartzTopShelfDemo服务
[Success] Description Quartz+TopShelf实现Windows服务作业调度的一个示例Demo
[Success] ServiceName QuartzTopShelfDemoService
23:23:52,185 INFO -Topshelf v3.3.154.0, .NET Framework v4.0.30319.34014
23:23:52,194 ERROR-The QuartzTopShelfDemoService service can only be installed as an administrator
23:25:54,758 INFO -Configuration Result:
[Success] Name QuartzTopShelfDemoService
[Success] DisplayName QuartzTopShelfDemo服务
[Success] Description Quartz+TopShelf实现Windows服务作业调度的一个示例Demo
[Success] ServiceName QuartzTopShelfDemoService
23:25:54,772 INFO -Topshelf v3.3.154.0, .NET Framework v4.0.30319.34014
23:25:54,781 DEBUG-Attempting to install 'QuartzTopShelfDemoService'
23:25:54,901 INFO -Installing QuartzTopShelfDemo服务 service
23:25:55,123 DEBUG-Opening Registry
23:25:55,123 DEBUG-Service path: "E:\DotNetProject\Y2016\QTDemo\QTDemo\bin\Release\QTDemo.exe"
23:25:55,123 DEBUG-Image path: "E:\DotNetProject\Y2016\QTDemo\QTDemo\bin\Release\QTDemo.exe" -displayname "QuartzTopShelfDemo服务" -servicename "QuartzTopShelfDemoService"
23:25:58,357 DEBUG-Closing Registry
23:28:10,442 INFO -Configuration Result:
[Success] Name QuartzTopShelfDemoService
[Success] DisplayName QuartzTopShelfDemo服务
[Success] Description Quartz+TopShelf实现Windows服务作业调度的一个示例Demo
[Success] ServiceName QuartzTopShelfDemoService
23:28:10,455 INFO -Topshelf v3.3.154.0, .NET Framework v4.0.30319.34014
23:28:10,649 DEBUG-Started by the Windows services process
23:28:10,649 DEBUG-Running as a service, creating service host.
23:28:10,651 INFO -Starting as a Windows service
23:28:10,654 DEBUG-[Topshelf] Starting up as a windows service application
23:28:10,657 INFO -[Topshelf] Starting
23:28:10,658 DEBUG-[Topshelf] Current Directory: E:\DotNetProject\Y2016\QTDemo\QTDemo\bin\Release
23:28:10,658 DEBUG-[Topshelf] Arguments:
23:28:10,940 INFO -[Topshelf] Started
23:28:10,988 INFO -TestJob测试
23:28:15,000 INFO -TestJob测试
23:28:20,000 INFO -TestJob测试

源码存网盘 quartz.net

qurtz.net(转载)的更多相关文章

  1. Crystal Clear Applied: The Seven Properties of Running an Agile Project (转载)

    作者Alistair Cockburn, Crystal Clear的7个成功要素,写得挺好. 敏捷方法的关注点,大家可以参考,太激动所以转载了. 原文:http://www.informit.com ...

  2. RTP与RTCP协议介绍(转载)

    RTSP发起/终结流媒体.RTP传输流媒体数据 .RTCP对RTP进行控制,同步.RTP中没有连接的概念,本身并不能为按序传输数据包提供可靠的保证,也不提供流量控制和拥塞控制,这些都由RTCP来负责完 ...

  3. 《Walking the callstack(转载)》

    本文转载自:https://www.codeproject.com/articles/11132/walking-the-callstack Download demo project with so ...

  4. [转载]MVVM模式原理分析及实践

    没有找到很好的MVVM模式介绍文章,简单找了一篇,分享一下.MVVM实现了UI\UE设计师(Expression Blend 4设计界面)和软件工程师的合理分工,在SilverLight.WPF.Wi ...

  5. [转载]:STM32为什么必须先配置时钟再配置GPIO

    转载来源 :http://blog.csdn.net/fushiqianxun/article/details/7926442 [原创]:我来添两句,就是很多同学(包括我)之前搞低端单片机,到了stm ...

  6. [转载]从MyEclipse到IntelliJ IDEA-让你摆脱鼠标,全键盘操作

    从MyEclipse转战到IntelliJ IDEA的经历 注转载址:http://blog.csdn.net/luoweifu/article/details/13985835 我一个朋友写了一篇“ ...

  7. TCP同步与异步,长连接与短连接【转载】

    原文地址:TCP同步与异步,长连接与短连接作者:1984346023 [转载说明:http://zjj1211.blog.51cto.com/1812544/373896   这是今天看到的一篇讲到T ...

  8. 在CentOS 7/6.5/6.4 中安装Java JDK 8(转载)

    转载在CentOS 7/6.5/6.4 中安装Java JDK 8 首先,在你的服务器上运行一下更新. yum update 然后,在您的系统上搜索,任何版本的已安装的JDK组件. rpm -qa | ...

  9. 用C#实现MD5的加密(转载)

    方法一 首先,先简单介绍一下MD5 MD5的全称是message-digest algorithm 5(信息-摘要算法,在90年代初由mit laboratory for computer scien ...

随机推荐

  1. Css学习(三)

    1 行高 ◆浏览器默认文字大小 浏览器默认文字大小:16px 行高:是基线与基线之间的距离 行高=文字高度+上下边距 一行文字行高和父元素高度一致的时候,垂直居中显示. 行高的单位 总结:单位除了像素 ...

  2. C# 自己动手实现Spy++(二)

    昨天已经实现了获取窗口的标题.句柄等信息,但是高亮部分还有问题,而且红色绘制框擦除也有问题,今天就又研究了下上述两个问题. 高亮部分红色框只显示左上的边框,而右下的显示不出来,如图: 代码如下: pu ...

  3. 7 家 IT 厂商 6394.5 万元中标天津公安云项目(虚拟化、数据库、软件开发)

    http://mp.weixin.qq.com/s/kjum54HJorGTPtZiM-HE1g 天津市公安局云计算平台项目分为:大数据部分.虚拟化部分.数据库部分,软件开发部分,预算分别为:2350 ...

  4. Android蓝牙BLE开发,扫描、连接、发送和读取信息;

    1.BLE开发权限 Android蓝牙BLE开发须打开蓝牙权限和6.0位置权限: <uses-permission android:name="android.permission.B ...

  5. json与bson的区别

    bson是由10gen开发的一个数据格式,目前主要用于mongoDB中,是mongoDB的数据存储格式.bson基于json格式,选择json进行改造的原因主要是json的通用性及json的schem ...

  6. bool操作

    基本类型转换的问题 bool类型没有操作. 类型转换 结论一: 想把xxx转化成yy类型. yy(xxx) 结论二: 能够表示False的数据: 0, "", [], {}, se ...

  7. sql语句基础(一)

    数据库基本操作  创建数据库  CREATE DATABASE database-nam 2.  删除数据库 drop database dbname 3. 备份sql server --- 创建 备 ...

  8. Faster RCNN原理分析(二):Region Proposal Networks详解

    Faster RCNN原理分析(二):Region Proposal Networks详解 http://lib.csdn.net/article/deeplearning/61641 0814: A ...

  9. 16. js方法传多个参数的实例

    field : 'operate',width : fixWidth(1/6),title : '操作',align : 'center',formatter : function(id,rowDat ...

  10. php图片上传base64数据编码。

    /** * base64图片上传 */ function IdImg($base64_img = ''){ $up_dir = 'upload/';//存放在当前目录的upload文件夹下 if(!f ...