在.NET CORE 3中使用Quartz.NET與Topshelf


之前做windows服務,使用的是Timer計時器來開發,做簡單的事情也還行,但做復雜的,還是有點麻煩,所以考慮用Topshelf與Quartz.NET來簡化一下。

Quartz.NET是一個強大、開源、輕量的作業調度框架,在項目中用來處理后台處理的任務,例如定時發送郵件通知、后台處理耗時的數據處理等,但在IIS部署的網站中應當注意應用程序池回收的問題。在所有.NET環境中都可以執行,包括但不限於winform、wpf、asp.net webform、asp.net mvc、控制台應用程序、windows服務,.net core等等

創建一個.net core 控制台應用程序,用NuGet包管理器安裝Quartz、Topshelf、Topshelf.Log4Net,如下圖

 先上一個Quartz的基本寫法

    internal class Program
    {        static async Task Main(string[] args)
        {
            //創建作業調度池
            var factory = new StdSchedulerFactory();
            var scheduler = await factory.GetScheduler();
            //創建出一個具體的作業
            var job = JobBuilder.Create<GreetingJob>().Build();
            //配置一個觸發器
            var trigger = (ISimpleTrigger)TriggerBuilder.Create()
                .WithSimpleSchedule(x => x.WithIntervalInSeconds(3).WithRepeatCount(int.MaxValue)).Build();
            //加入作業調度池中
            await scheduler.ScheduleJob(job, trigger);
            //開始運行
            await scheduler.Start();
            Console.ReadKey();
        }
    }
   [DisallowConcurrentExecution] //禁止並發執行
    public class GreetingJob : IJob
    {
        //private readonly ILog _logger = LogManager.GetLogger(typeof(GreetingJob));
        public Task Execute(IJobExecutionContext context)
        {
            Console.WriteLine($"{DateTime.Now}:你好嗎?----From GreetingJob");
            //_logger.Info($"{DateTime.Now}:你好嗎?----From GreetingJob");
            Thread.Sleep(3000);
            return Task.FromResult(true);
        }
    }

跑起來就是這個造型,3秒執行一次

 

 

 在Quartz.net中有兩種觸發器類型,一種是簡單觸發器,也就是上面的ISimpleTrigger接口,還有一種是Cron類型的觸發器,對應的接口名是ICronTrigger,他使用cron表達式來描述Job的觸發事件,這樣可以處理更加復雜一些的需求,比如要每天在特定時間點執行(上午 10:00 及 下午 6:00),或者是特定日期執行 (每月5號) 等特殊需求,而這個就是 Quartz.Net 的強項啦,透過其 cron 來描述作業被觸發的週期,從秒、分、時、日、月、星期、年都可以進行操作。

"10,20,25 * * * * ? *":每分鍾的第10、20、25秒會執行

"10 0/5 * * * ?":每5分鍾的第10秒會執行 (ex. 10:00:10 am, 10:05:10 am ...)

"0 20 10-13 ? * WED,FRI":每星期三與星期五的 10:20, 11:20, 12:20, 13:20 執行

"0 0/30 8-9 5,20 * ?":每月5號及20號的 8:00, 8:30, 9:00, 9:30 執行

遇到復雜的情境,無法使用單一表示式來定義,可以考慮定義多個 Trigger 來觸發相同 Job 。

            var trigger = (ICronTrigger)TriggerBuilder.Create().WithIdentity("Main","Main")
                .WithCronSchedule("10,20,25 * * * * ? *").StartAt(DateTime.UtcNow).WithPriority(1).Build();

直接上加了Topshelf的代碼,飯點吃飯去了,你品,你細細的品......

using log4net;
using log4net.Repository;
using Quartz;
using Quartz.Impl;
using System;
using System.Threading;
using System.Threading.Tasks;
using Topshelf;

namespace QuartzConsoleApp
{
    internal class Program
    {
        private static ILoggerRepository _loggerRepository= LogManager.CreateRepository("rmb");
        //static async Task Main(string[] args)
        static void Main(string[] args)
        {
            try
            {
                // 配置和運行宿主服務
                HostFactory.Run(x =>
                {
                    x.UseLog4Net("App.config");
                    x.Service<ServiceRunner>(s =>
                    {
                        // 指定服務類型。這里設置為 Service
                        s.ConstructUsing(name => new ServiceRunner());

                        // 當服務啟動后執行什么
                        s.WhenStarted((sc, hc) => sc.Start(hc));

                        // 當服務停止后執行什么
                        s.WhenStopped((sc, hc) => sc.Stop(hc));
                    });

                    // 服務用本地系統賬號來運行
                    x.RunAsLocalSystem();
                    //x.StartAutomaticallyDelayed();
                    x.StartAutomatically();

                    // 服務描述信息
                    x.SetDescription("測試Greeting服務,此處是服務描述信息");
                    // 服務顯示名稱
                    x.SetDisplayName("測試Greeting服務");
                    // 服務名稱
                    x.SetServiceName("GreetingJobService");
                });
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
    }

    [DisallowConcurrentExecution] //禁止並發執行
    public class GreetingJob : IJob
    {
        private readonly ILog _logger = LogManager.GetLogger(typeof(GreetingJob));
        public Task Execute(IJobExecutionContext context)
        {
            //Console.WriteLine($"{DateTime.Now}:你好嗎?----From GreetingJob");
            _logger.Info($"{DateTime.Now}:你好嗎?----From GreetingJob");
            Thread.Sleep(3000);
            return Task.FromResult(true);
        }
    }


    public sealed class ServiceRunner : ServiceControl, ServiceSuspend
    {
        //調度器
        private readonly IScheduler scheduler;

        public ServiceRunner()
        {
            scheduler = StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult();
            //創建出一個具體的作業
            var job = JobBuilder.Create<GreetingJob>().Build();
            //配置一個觸發器
            var trigger = (ISimpleTrigger)TriggerBuilder.Create()
                .WithSimpleSchedule(x => x.WithIntervalInSeconds(3).WithRepeatCount(int.MaxValue)).Build();
            //加入作業調度池中
            scheduler.ScheduleJob(job, trigger);
        }

        //開始
        public bool Start(HostControl hostControl)
        {
            scheduler.Start();
            return true;
        }

        //停止
        public bool Stop(HostControl hostControl)
        {
            scheduler.Shutdown(false);
            return true;
        }

        //恢復所有
        public bool Continue(HostControl hostControl)
        {
            scheduler.ResumeAll();
            return true;
        }

        //暫停所有
        public bool Pause(HostControl hostControl)
        {
            scheduler.PauseAll();
            return true;
        }

    }
}

配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <log4net>
    <appender name="ManagedColoredConsoleAppender" type="log4net.Appender.ManagedColoredConsoleAppender">
      <mapping>
        <level value="ERROR" />
        <foreColor value="Red" />
      </mapping>
      <mapping>
        <level value="Info" />
        <foreColor value="Green" />
      </mapping>
      <mapping>
        <level value="DEBUG" />
        <foreColor value="Blue" />
      </mapping>
      <mapping>
        <level value="WARN" />
        <foreColor value="Yellow" />
      </mapping>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%d{ABSOLUTE} [%thread] %-5p %c{1}:%L - %m%n" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMin" value="DEBUG" />
        <param name="LevelMax" value="Fatal" />
      </filter>
    </appender>
    <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <file value=".\logs\" />
      <datePattern value="'GreetingJobService_'yyyy.MM.dd'.log'" />
      <staticLogFileName value="false" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="5MB" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%d [%t] %-5p %c - %m%n" />
      </layout>
    </appender>
    <root>
      <level value="all" />
      <appender-ref ref="ManagedColoredConsoleAppender" />
      <appender-ref ref="RollingFile" />
    </root>
  </log4net>
</configuration>

 調試效果

 

 

部署、開始、卸載服務只需要一句命令行就可以:

    安裝:你的程序.exe install
    啟動:你的程序.exe start
    卸載:你的程序.exe uninstall
更多命令:你的程序.exe help

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM