【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
 
 
参考资料:
 
posted @ 2017-04-13 19:38  清幽火焰  阅读(397)  评论(0编辑  收藏  举报