【10】Quartz.net 定时服务实例
一.安装nuget包
Install-Package Quartz
Install-Package Common.Logging.Log4Net1211
Install-Package log4net
Install-Package
Topshelf
二.添加IQuartzServer接口类
/// <summary> /// Service interface for core Quartz.NET server. /// </summary> public interface IQuartzServer { /// <summary> /// Initializes the instance of <see cref="IQuartzServer"/>. /// Initialization will only be called once in server's lifetime. /// </summary> void Initialize(); /// <summary> /// Starts this instance. /// </summary> void Start(); /// <summary> /// Stops this instance. /// </summary> void Stop(); /// <summary> /// Pauses all activity in scheduler. /// </summary> void Pause(); /// <summary> /// Resumes all activity in server. /// </summary> void Resume(); }
三.添加QuartzServer类实现接口
public class QuartzServer : ServiceControl, IQuartzServer { private readonly ILog logger; private ISchedulerFactory schedulerFactory; private IScheduler scheduler; /// <summary> /// Initializes a new instance of the <see cref="QuartzServer"/> class. /// </summary> public QuartzServer() { logger = LogManager.GetLogger(GetType()); } /// <summary> /// Initializes the instance of the <see cref="QuartzServer"/> class. /// </summary> public virtual void Initialize() { try { schedulerFactory = CreateSchedulerFactory(); scheduler = GetScheduler(); } catch (Exception e) { logger.Error("Server initialization failed:" + e.Message, e); throw; } } /// <summary> /// Gets the scheduler with which this server should operate with. /// </summary> /// <returns></returns> protected virtual IScheduler GetScheduler() { return schedulerFactory.GetScheduler(); } /// <summary> /// Returns the current scheduler instance (usually created in <see cref="Initialize" /> /// using the <see cref="GetScheduler" /> method). /// </summary> protected virtual IScheduler Scheduler { get { return scheduler; } } /// <summary> /// Creates the scheduler factory that will be the factory /// for all schedulers on this instance. /// </summary> /// <returns></returns> protected virtual ISchedulerFactory CreateSchedulerFactory() { return new StdSchedulerFactory(); } /// <summary> /// Starts this instance, delegates to scheduler. /// </summary> public virtual void Start() { try { scheduler.Start(); } catch (Exception ex) { logger.Fatal(string.Format("Scheduler start failed: {0}", ex.Message), ex); throw; } logger.Info("Scheduler started successfully"); } /// <summary> /// Stops this instance, delegates to scheduler. /// </summary> public virtual void Stop() { try { scheduler.Shutdown(true); } catch (Exception ex) { logger.Error(string.Format("Scheduler stop failed: {0}", ex.Message), ex); throw; } logger.Info("Scheduler shutdown complete"); } /// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> public virtual void Dispose() { // no-op for now } /// <summary> /// Pauses all activity in scheduler. /// </summary> public virtual void Pause() { scheduler.PauseAll(); } /// <summary> /// Resumes all activity in server. /// </summary> public void Resume() { scheduler.ResumeAll(); } /// <summary> /// TopShelf's method delegated to <see cref="Start()"/>. /// </summary> public bool Start(HostControl hostControl) { Start(); return true; } /// <summary> /// TopShelf's method delegated to <see cref="Stop()"/>. /// </summary> public bool Stop(HostControl hostControl) { Stop(); return true; } /// <summary> /// TopShelf's method delegated to <see cref="Pause()"/>. /// </summary> public bool Pause(HostControl hostControl) { Pause(); return true; } /// <summary> /// TopShelf's method delegated to <see cref="Resume()"/>. /// </summary> public bool Continue(HostControl hostControl) { Resume(); return true; } }
四.添加服务工厂QuartzServerFactory
public class QuartzServerFactory { private static readonly ILog logger = LogManager.GetLogger(typeof(QuartzServerFactory)); /// <summary> /// Creates a new instance of an Quartz.NET server core. /// </summary> /// <returns></returns> public static QuartzServer CreateServer() { string typeName = "QuartzTest.QuartzServer"; Type t = Type.GetType(typeName, true); logger.Debug("Creating new instance of server type '" + typeName + "'"); QuartzServer retValue = (QuartzServer)Activator.CreateInstance(t); logger.Debug("Instance successfully created"); return retValue; } }
五.添加Job类
/// <summary> /// A sample job that just prints info on console for demostration purposes. /// </summary> public class SampleJob : IJob { private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); //private static readonly ILog logger = LogManager.GetLogger(typeof(SampleJob)); /// <summary> /// Called by the <see cref="IScheduler" /> when a <see cref="ITrigger" /> /// fires that is associated with the <see cref="IJob" />. /// </summary> /// <remarks> /// The implementation may wish to set a result object on the /// JobExecutionContext before this method exits. The result itself /// is meaningless to Quartz, but may be informative to /// <see cref="IJobListener" />s or /// <see cref="ITriggerListener" />s that are watching the job's /// execution. /// </remarks> /// <param name="context">The execution context.</param> public void Execute(IJobExecutionContext context) { logger.Info("SampleJob running..."); Thread.Sleep(TimeSpan.FromSeconds(5)); logger.Info("SampleJob run finished."); } }
六.添加quartz.config配置文件
# You can configure your scheduler in either <quartz> configuration section # or in quartz properties file # Configuration section has precedence quartz.scheduler.instanceName = ServerScheduler # configure thread pool info quartz.threadPool.type = Quartz.Simpl.SimpleThreadPool, Quartz quartz.threadPool.threadCount = 10 quartz.threadPool.threadPriority = Normal # job initialization plugin handles our xml reading, without it defaults are used quartz.plugin.xml.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz quartz.plugin.xml.fileNames = ~/quartz_jobs.xml # export this server to remoting context quartz.scheduler.exporter.type = Quartz.Simpl.RemotingSchedulerExporter, Quartz quartz.scheduler.exporter.port = 555 quartz.scheduler.exporter.bindName = QuartzScheduler quartz.scheduler.exporter.channelType = tcp quartz.scheduler.exporter.channelName = httpQuartz
七.添加quartz_jobs.xml配置job
<?xml version="1.0" encoding="UTF-8"?> <!-- This file contains job definitions in schema version 2.0 format --> <job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"> <processing-directives> <overwrite-existing-data>true</overwrite-existing-data> </processing-directives> <schedule> <job> <name>sampleJob</name> <group>sampleGroup</group> <description>Sample job for Quartz Server</description> <job-type>QuartzTest.SampleJob, QuartzTest</job-type> <durable>true</durable> <recover>false</recover> </job> <trigger> <simple> <name>sampleSimpleTrigger</name> <group>sampleSimpleGroup</group> <description>Simple trigger to simply fire sample job</description> <job-name>sampleJob</job-name> <job-group>sampleGroup</job-group> <misfire-instruction>SmartPolicy</misfire-instruction> <repeat-count>-1</repeat-count> <repeat-interval>10000</repeat-interval> </simple> </trigger> </schedule> </job-scheduling-data>
八.app.config文件修改
<?xml version="1.0" encoding="utf-8"?> <configuration> <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.Log4net1213"> <arg key="configType" value="INLINE" /> </factoryAdapter> </logging> </common> <log4net> <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> <!--日志文件名开头--> <file value="D:\Log\Quartz\log_"/> <!--多线程时采用最小锁定--> <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/> <!--日期的格式,每天换一个文件记录,如不设置则永远只记录一天的日志,需设置--> <datePattern value="yyyyMMdd_HH".log""/> <!--是否追加到文件,默认为true,通常无需设置--> <appendToFile value="true"/> <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])--> <RollingStyle value="Composite"/> <!--每天记录的日志文件个数,与maximumFileSize配合使用--> <MaxSizeRollBackups value="100"/> <!--每个日志文件的最大大小--> <!--可用的单位:KB|MB|GB--> <!--不要使用小数,否则会一直写入当前日志--> <maximumFileSize value="2MB"/> <!--是否只写到一个文件中--> <staticLogFileName value="false" /> <!--日志格式--> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%t]%-5p %c - %m%n"/> </layout> </appender> <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%d [%t] %-5p %l - %m%n" /> </layout> </appender> <appender name="EventLogAppender" type="log4net.Appender.EventLogAppender"> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%d [%t] %-5p %l - %m%n" /> </layout> </appender> <root> <level value="ALL" /> <appender-ref ref="ConsoleAppender" /> <appender-ref ref="RollingFileAppender" /> <!--控制级别,由低到高: ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF--> <!-- uncomment to enable event log appending --> <!-- <appender-ref ref="EventLogAppender" /> --> </root> </log4net> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" /> </startup> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-2.0.8.0" newVersion="2.0.8.0" /> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
九.主程序代码
static void Main(string[] args) { log4net.Config.XmlConfigurator.Configure(); // change from service account's dir to more logical one Directory.SetCurrentDirectory(System.AppDomain.CurrentDomain.BaseDirectory); ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); logger.Info("日志开始"); HostFactory.Run(x => { x.RunAsLocalSystem(); x.SetDescription("QuartzDemo服务描述"); x.SetDisplayName("QuartzDemo服务显示名称"); x.SetServiceName("QuartzDemo服务名称"); x.Service(factory => { QuartzServer server = QuartzServerFactory.CreateServer(); server.Initialize(); return server; }); }); }
十.运行
每10秒运行一次job
参考资料: