【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


参考资料:









  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值