Quartz .Net( 二) :可视化界面、xml配置、window服务自启动

可视化界面

首先新建一个web项目,其框架为.Net Framework4.5.2,然后需要添加引入Quartz和CrystalQuartz.Remote两个Nuget包。之后我们可以在项目的web.config中看到其为我们添加了以下的一些节点。其中添加的 handler 用来处理我们访问路径 CrystalQuartzPanel.axd时的处理程序,而provider中提供的端口8008则是用来做此web与quartz中的scheduler通信的端口。

<configSections>
    <sectionGroup name="crystalQuartz" type="CrystalQuartz.Web.Configuration.CrystalQuartzConfigurationGroup">
       <section name="provider" type="CrystalQuartz.Web.Configuration.ProviderSectionHandler" requirePermission="false" allowDefinition="Everywhere" />
    </sectionGroup>
</configSections>
<handlers>
  <add name="CrystalQuartzPanel" verb="*" path="CrystalQuartzPanel.axd" type="CrystalQuartz.Web.PagesHandler, CrystalQuartz.Web" />
</handlers>

<crystalQuartz>
  <provider>
    <add property="Type" value="CrystalQuartz.Core.SchedulerProviders.RemoteSchedulerProvider, CrystalQuartz.Core" />
    <!-- Edit scheduler host value below =================================== -->
    <add property="SchedulerHost" value="tcp://localhost:8008/QuartzScheduler" />
    <!-- =================================== -->
  </provider>
</crystalQuartz>

那么Quartz.Net中的Scheduler如何与其通信呢?在StdSchedulerFactory的构造函数中有一个带参构造函数,可以通过配置一些属性来实现。

public StdSchedulerFactory(NameValueCollection props)

具体属性设置如下

public class ScheduleManager
{
    public async static Task<IScheduler> BuildScheduler()
    {
        var properties = new NameValueCollection();
        properties["quartz.scheduler.instanceName"] = "后台作业监控系统";

        // 设置线程池
        properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
        properties["quartz.threadPool.threadCount"] = "5";
        properties["quartz.threadPool.threadPriority"] = "Normal";

        // 远程输出配置
        properties["quartz.scheduler.exporter.type"] = "Quartz.Simpl.RemotingSchedulerExporter, Quartz";
        properties["quartz.scheduler.exporter.port"] = "8008";
        properties["quartz.scheduler.exporter.bindName"] = "QuartzScheduler";
        properties["quartz.scheduler.exporter.channelType"] = "tcp";

        var schedulerFactory = new StdSchedulerFactory(properties);
        IScheduler _scheduler = await schedulerFactory.GetScheduler();
        return _scheduler;
    }
}

然后通过ScheduleManager.BuildScheduler()来创建IScheduler,就可以通过可视化界面来监控和管理我们的定时任务了。

在打开的网站后加上webconfig 黄色标记的那个Path值上去,回车,即可,效果如下图

 

 

 

 

 

 

 

 

 

xml配置

前面介绍的任务的创建执行是通过代码来实现的,当要添加一个任务的时候就非常的不灵活,做不到热插拔。而通过配置文件的方式实现配置化,可以做到在添加一个任务的话,我们可以新建一个类库来定义Job做到热插拔。

  具体实现方法也很简单,创建一个配置文件quartz_job.config,其定义了 CheckPaymentStateJob 和  CheckPaymentStateTrigger1的一个配置。

XMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(new SimpleTypeLoadHelper());
await processor.ProcessFileAndScheduleJobs("~/config/quartz_job.config", scheduler);

 

<?xml version="1.0" encoding="UTF-8"?>
<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>CheckPaymentStateJob</name>
      <group>CheckStateGroup</group>
      <description>支付状态回调检查</description>
      <job-type>DispatcherProject.QuartzNet.CheckJob.CheckPaymentStateJob,DispatcherProject.QuartzNet</job-type>
      <durable>true</durable>
      <recover>false</recover>
    </job>
    <trigger>
      <cron>
        <name>CheckPaymentStateTrigger1</name>
        <group>CheckState</group>
        <job-name>CheckPaymentStateJob</job-name>
        <job-group>CheckStateGroup</job-group>
        <cron-expression>0 0/1 * * * ?</cron-expression>
      </cron>
    </trigger>
    
  </schedule>
</job-scheduling-data>

而最后需要做的就是将该配置文件添加到Scheduler中就可以了。

XMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(new SimpleTypeLoadHelper());
await processor.ProcessFileAndScheduleJobs("~/config/quartz_job.config", scheduler);

window服务自启动

之前的介绍都是基于Web的,这种实现任务调度的方式很少见,因为不管是MVC、WebApi还是WebService,它们都需要寄宿在IIS上运行,然而我们知道IIS是会定时回收进程池的,在一段时间内如果该站点没有收到任何请求,其就会进行回收,等到下次请求再自动启动。这样如果我们的任务需要在某个固定时间点执行就无法保障了。

  因此,采用Windows Service来实现定时任务是更加合适的,它是由操作系统进行调度的,我们可以设置将服务设置为自启动,它将随着操作系统的启动而运行该进程。

  新建一个Windows Service项目,其会为我们创建一个主入口

static class Program
{
    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    static void Main()
    {
        try
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
            new Service1()
            };
            ServiceBase.Run(ServicesToRun);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            throw;
        }

    }
}

我们可以通过在Service1中来启动定时任务,通过log4net可以记录一些必要的日志

public partial class Service1 : ServiceBase
{
    private Logger logger = new Logger(typeof(Service1));
    public Service1()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        this.logger.Info("This is OnStart..");

        IScheduler scheduler = await ScheduleManager.BuildScheduler();

        //使用配置文件
        XMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(new SimpleTypeLoadHelper());
        await processor.ProcessFileAndScheduleJobs("~/config/quartz_jobs.config", scheduler);
        
    }

    protected override void OnStop()
    {
        this.logger.Info("This is OnStop..");
    }
}
<?xml version="1.0" encoding="utf-8"?>
<log4net>
    <!-- Define some output appenders -->
    <appender name="rollingAppender" type="log4net.Appender.RollingFileAppender">
        <file value="log\log.txt" />

        <!--追加日志内容-->
        <appendToFile value="true" />

        <!--防止多线程时不能写Log,官方说线程非安全-->
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />

        <!--可以为:Once|Size|Date|Composite-->
        <!--Composite为Size和Date的组合-->
        <rollingStyle value="Composite" />

        <!--当备份文件时,为文件名加的后缀-->
        <datePattern value="yyyyMMdd.TXT" />

        <!--日志最大个数,都是最新的-->
        <!--rollingStyle节点为Size时,只能有value个日志-->
        <!--rollingStyle节点为Composite时,每天有value个日志-->
        <maxSizeRollBackups value="20" />

        <!--可用的单位:KB|MB|GB-->
        <maximumFileSize value="3MB" />

        <!--置为true,当前最新日志文件名永远为file节中的名字-->
        <staticLogFileName value="true" />

        <!--输出级别在INFO和ERROR之间的日志-->
        <filter type="log4net.Filter.LevelRangeFilter">
            <param name="LevelMin" value="INFO" />
            <param name="LevelMax" value="FATAL" />
        </filter>

        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
        </layout>
    </appender>

    <!-- levels: OFF > FATAL > ERROR > WARN > INFO > DEBUG  > ALL -->
    <root>
        <priority value="ALL"/>
        <level value="ALL"/>
        <appender-ref ref="rollingAppender" />
    </root>
</log4net>
public class Logger
{
    static Logger()
    {
        XmlConfigurator.Configure(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config\\log4net.config")));
        ILog Log = LogManager.GetLogger(typeof(Logger));
        Log.Info("系统初始化Logger模块");
    }

    private ILog loger = null;
    public Logger(Type type)
    {
        loger = LogManager.GetLogger(type);
    }

    /// <summary>
    /// Log4日志
    /// </summary>
    /// <param name="msg"></param>
    /// <param name="ex"></param>
    public void Error(string msg = "出现异常", Exception ex = null)
    {
        loger.Error(msg, ex);
    }

    /// <summary>
    /// Log4日志
    /// </summary>
    /// <param name="msg"></param>
    public void Warn(string msg)
    {
        loger.Warn(msg);
    }

    /// <summary>
    /// Log4日志
    /// </summary>
    /// <param name="msg"></param>
    public void Info(string msg)
    {
        loger.Info(msg);
    }

    /// <summary>
    /// Log4日志
    /// </summary>
    /// <param name="msg"></param>
    public void Debug(string msg)
    {
        loger.Debug(msg);
    }

}

 最后我们可以在Service1的界面上右键添加安装程序,来设置服务的一些信息。

 

 

 

 

 接着通过编译完成后就可以通过下面的命令来安装或卸载服务了

C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil  QuartzProject.WindowsService.exe

C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil /u  QuartzProject.WindowsService.exe
服务改名称后,需要先原样卸载,再重新编译安装,要不然卸载还蛮麻烦的

 内容出处:https://www.cnblogs.com/jesen1315/p/11653181.html

posted @ 2020-03-12 17:27  明志德道  阅读(2182)  评论(0)    收藏  举报