Topshelf结合Quartz.NET实现服务端定时调度任务

这周接受到一个新的需求:一天内分时间段定时轮询一个第三方WebAPI,并保存第三方WebAPI结果。

需求分析:分时段、定时开启、定时结束、轮询。主要工作集中在前三个上,轮询其实就是个Http请求,比较好解决。

技术选型:

  1、最简单的方式:Windows Service、Timer、HttpClient。
  2、B格高点的方式:Topshelf、Quartz.NET、HttpClient。
之所以选用第二种方式的原因:

  1、Windows Service尝试写了一个,发现附加进程调试确实麻烦,而且以后若是需求变更,还需要重新调试发布Windows Service

  2、Timer需要在项目中建立多个,区分起来着实麻烦

  3、刚好在学习使用Quartz.NET,打算过段时间做个MVC版本的调度任务管理系统

  4、经过查找cnblog发现,使用Topshelf可以用基于Console的模式先编写、调试程序,等调试通过后,用Topshelf命令即可完成Windows Service安装,据说还可以在Linux上通过Mono安装,也算是可以支持跨平台的咯(*^_^*)或许也可以通过制作Docker镜像来实现。

Show Code:

1、添加依赖Nuget包:Topshelf、Topshelf.Log4Net、Quartz、Common.Logging、Common.Logging.Core、Common.Logging.Log4Net1211、log4Net

2、创建ServiceRunner.cs类,继承ServiceControl, ServiceSuspend,这是为了用Topshelf的Start()、Stop()、Continue()、Pause()来分别执行Quartz任务调度的Start()、Shutdown()、ResumeAll()、PauseAll()方法

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

3、我在这里采用Topshelf的Custom Service模式,在Main()方法中写如下代码

 1 HostFactory.Run(x =>
 2             {
 3                 x.UseLog4Net();
 4                 x.Service<ServiceRunner>();
 5                 x.SetDescription("QuartzDemo服务描述");
 6                 x.SetDisplayName("QuartzDemo服务显示名称");
 7                 x.SetServiceName("QuartzDemo服务名称");
 8
 9                 x.EnablePauseAndContinue();
10             });

4、到此为止,建Windows Service的工作算是基本结束,接下来就是重点了,如何用Quartz做一个定时任务。但是这个过程并不难,这里我采用的是Quartz的Cron模式,相比较Simple模式,此种模式通过配置来制定Trigger触发和Job的执行,在我的Windows Service创建好后,无须我再次编译,只需要替换进一个实现IJob接口的动态链接库,并且在Quartz_jobs.xml配置即可,实现IJob的测试代码如下:

 1 public class TestJob : IJob
 2     {
 3         private readonly ILog _log = LogManager.GetLogger(typeof(TestJob));
 4         public void Execute(IJobExecutionContext context)
 5         {
 6
 7             _log.Info("测试Job,时间:"+ DateTime.Now.ToString("r"));
 8
 9         }
10     }

5、准备Quartz.NET的配置文件quartz.config、quartz_jobs.xml,Quartz的Initialize()方法默认从编译输出目录下读取quartz.config文件,并且在quartz.config文件增加quartz.plugin.xml.fileNames 节点写 ~/quartz_jobs.xml,用来配置Trigger和Job的执行

 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.config

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

quartz_jobs.xml

6、至此,我们已经基本可以把项目run起来了,但是这只能在console上看到每三秒打印一行“测试Job,时间:***”,并不能确定在以Windows Service时,定时任务调度也能按计划执行,我们还需要将日志输出到文件,需要继续配置log4Net

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

log4net.config

同时在Main()方法中增加一行读取log4Net配置文件的代码,另:quartz.config、quartz_jobs.xml、log4net.config这三个文件,分别选中→右键属性→复制到输入目录设为:始终复制

 1         static void Main(string[] args)
 2         {
 3             log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "log4net.config"));
 4             HostFactory.Run(x =>
 5             {
 6                 x.UseLog4Net();
 7                 x.Service<ServiceRunner>();
 8                 x.SetDescription("QuartzDemo服务描述");
 9                 x.SetDisplayName("QuartzDemo服务显示名称");
10                 x.SetServiceName("QuartzDemo服务名称");
11
12                 x.EnablePauseAndContinue();
13             });
14         }

最后,我们还需要将Topshelf注册到Windows中,在CMD中打开debug文件夹,Topshelf命令如下,

安装:WindowsService.exe install

启动:WindowsService.exe start

卸载:WindowsService.exe uninstall

至此,算是基本完成,我接下来只需要在一个继承IJob的类中实现业务代码即可。(*^_^*)

参考

Quartz.NET

官方学习文档:http://www.quartz-scheduler.net/documentation/index.html

使用实例介绍:http://www.quartz-scheduler.net/documentation/quartz-2.x/quick-start.html

官方的源代码下载:http://sourceforge.net/projects/quartznet/files/quartznet/

Topself文档:http://topshelf-project.com/

Log4Net文档:http://logging.apache.org/log4net/

时间: 2024-10-11 14:31:44

Topshelf结合Quartz.NET实现服务端定时调度任务的相关文章

TopShelf+Quartz.net实现基于window服务的定时调度

由于发布网站上Quartz.net的定时调度会被IIS回收不执行,解决的方法写Windows服务-案列[每天早晨8点删除过期35天的域名] 整了个三成架构:从Nuget成程序管理包下载Quart类库和TopShelf类库 1.创建定时调度Quartz类 1 class QuartzServiceRunner 2 { 3 private readonly IScheduler scheduler; 4 5 public QuartzServiceRunner() 6 { 7 scheduler =

Windows下cwrsync客户端与rsync群辉存储服务端定时数据同步

cwRsync简介 cwRsync是Rsync在Windows上的实现版本,Rsync通过使用特定算法的文件传输技术,可以在网络上传输只修改了的文件. cwRsync主要用于Windows上的远程文件同步备份和同步,它包含Cygwin DLL和适用Cygwin版本的Rsync两部分. cwRsync分为Server和Client,本文使用的版本为4.1.0 实现目的:把Windows客户端D:\data目录的数据通过计划任务实现定时自动同步到群辉存储服务端192.168.85.8\NetBack

API设计风格(RRC、REST、GraphQL、服务端驱动)

Web API设计其实是一个挺重要的设计话题,许多公司都会有公司层面的Web API设计规范,几乎所有的项目在详细设计阶段都会进行API设计,项目开发后都会有一份API文档供测试和联调.本文尝试根据自己的理解总结一下目前常见的四种API设计风格以及设计考虑点. RPC 这是最常见的方式,RPC说的是本地调用远程的方法,面向的是过程. RPC形式的API组织形态是类和方法,或者说领域和行为. 因此API的命名往往是一个动词,比如GetUserInfo,CreateUser. 因为URI会非常多而且

windows 服务实现定时任务调度(Quartz.Net)

我们通常在一些情况下需要软件具有一个自动执行某些任务的功能,但是又不希望直接启动软件,或者每次都要手动的来启动软件,这时我们可可以考虑到windows服务了. 首先创建一个windows服务项目(详细信息请参阅:C#创建Windows Service(Windows 服务)基础教程) 在创建好的项目中点击“单击此处切换到代码视图”切换到代码 我们主要关注一下两个方法: • OnStart – 控制服务启动 • OnStop – 控制服务停止 例: 1 public partial class S

SpringMVC + Mybatis + SpringSecurity(权限控制到方法按钮) + Rest(服务) + Webservice(服务) + Quartz(定时调度)+ Lucene(搜索引擎) + HTML5 bootstrap + Maven项目构建绝对开源平台

框架整合: Springmvc + Mybatis + Shiro(权限) + REST(服务) + WebService(服务) + JMS(消息) + Lucene(搜搜引擎) + Quartz(定时调度) + Bootstrap Html5(支持PC.IOS.Android) 需要源码请加Q:3121026417   此处[源码获取地址] 框架简介: 项目Maven构建,真实大型互联网架构,做到高并发,大数据处理,整个项目使用定制化服务思想,提供模块化.服务化.原子化的方案,将功能模块进行

Ajax轮询——“定时的通过Ajax查询服务端”

Ajax轮询——"定时的通过Ajax查询服务端". 概念: 轮询(polling):客户端按规定时间定时像服务端发送ajax请求,服务器接到请求后马上返回响应信息并关闭连接. 百闻不如一见,来段代码相信你一看就明白 //为了让同学们都明白,我用了最简单的实现方法,同学们懂了原理后可以自行衍生: Reception.html //前端代码 <html> <head> <title></title> <script src="

定时调度系列之Quartz.Net详解(转)

出处:https://www.cnblogs.com/yaopengfei/p/9216229.html 一. 背景 我们在日常开发中,可能你会遇到这样的需求:"每个月的3号给用户发信息,提醒用户XXX "."每天的0点需要统计前一天的考勤记录"."每个月的1号计算上个月的库存情况"."定时初始化数据供其它业务使用"."每隔2分钟轮询查数据库看某业务是否被审核通过,并提示用户" 等等. 以上需求在开发中都非

使用NewLife网络库构建可靠的自动售货机Socket服务端(一)

最近有个基于tcp socket 协议和设备交互需求,想到了新生命团队的各种组件,所以决定用NewLife网络库作为服务端来完成一系列的信息交互. 第一,首先说一下我们需要实现的功能需求吧 1,首先客户有一堆自动售货机的设备,设备连接socket服务端后 定时发送设备实时状态作为心跳信息,并且服务端需要下发信息予以确认. 2,需要知道设备的实时在线状态 3,设备需要实现微信,支付宝扫码支付需求,当客户买东西的时候选择扫码支付时,设备上报产品价格信息,支付方式,服务器下发微信或者支付宝的当面付二维

谈一款MOBA类游戏《码神联盟》的服务端架构设计与实现

一.前言 <码神联盟>是一款为技术人做的开源情怀游戏,每一种编程语言都是一位英雄.客户端和服务端均使用C#开发,客户端使用Unity3D引擎,数据库使用MySQL.这个MOBA类游戏是笔者在学习时期和客户端美术策划的小伙伴一起做的游戏,笔者主要负责游戏服务端开发,客户端也参与了一部分,同时也是这个项目的发起和负责人.这次主要分享这款游戏的服务端相关的设计与实现,从整体的架构设计,到服务器网络通信底层的搭建,通信协议.模型定制,再到游戏逻辑的分层架构实现.同时这篇博客也沉淀了笔者在游戏公司实践五