過場CG:
接到公司領導的文件指示,「小熊」須要在6月底去海外執行一個行動代號爲【定時任務】的營救計劃,這個計劃關係到公司某個項目的生死(數據安全漏洞),做戰部擬定兩個做戰方案:
方案一:使用務定時任務框架quartz;
方案二:使用windows Service服務。
最終的做戰方案爲:二者配套使用。
|
1、開發環境html
操做系統:Windows 7 X64/32數據庫
開發環境:VS2017編程
編程語言:C#windows
.NET版本:.NET Framework 4.6.1安全
2、建立Windows Service微信
一、新建一個Windows Service,並將項目名稱改成「MyWindowsService」,以下圖所示:併發
二、在解決方案資源管理器內將Service1.cs改成MyWindowsService.cs後並在左邊頁面空白處點擊鼠標右鍵,添加安裝程序,以下圖所示:微信公衆平臺
添加安裝程序:框架
三、 此時軟件會生成兩個組件,分別爲「serviceInstaller1」及「serviceProcessInstaller1」,點擊「serviceInstaller1」,右鍵--->屬性,編程語言
將ServiceName改成MyWindowsService,Description改成「個人服務」,以下圖:
四、點擊「serviceProcessInstaller1」,在「屬性」窗體將Account改成LocalSystem(服務屬性系統級別),以下圖所示:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Linq; using System.ServiceProcess; using System.Text; using System.Threading; using System.Threading.Tasks; namespace MyWindowsService { public partial class MyWindowsService : ServiceBase { public MyWindowsService() { InitializeComponent(); } //建立進程 public static Thread threadStartConfirmActualTime; //建立一個時間進程 public static Thread threadDoCheck; //檢查日誌時間進程 //開啓服務 protected override void OnStart(string[] args) { Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\t服務啓動!\n"); StartServer(); } //中止服務 protected override void OnStop() { Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\t服務中止!\n"); } //啓動服務操做 private void StartServer() { try { threadStartConfirmActualTime = new Thread(new ThreadStart(new SingleClass().BeginConfirmMessageTime));//在進程下面建立線程 threadStartConfirmActualTime.Start(); threadDoCheck.Start(); } catch (Exception ex) { threadStartConfirmActualTime.Abort();//關閉線程 Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\t服務中止!"+ex.Message+"\n"); } } /// <summary> /// Aouth:xiongze /// Time:2020/06/02 /// Details:單例模式_創建一個單例類,保證只有一個對象被實例化,而後開啓服務 /// </summary> public class SingleClass //單例模式_創建一個單例類,保證只有一個對象被實例化 { public static SingleClass _SingleClass; public static object onlock = new object(); //實例化一個鎖 public static SingleClass Singleton { get { if (_SingleClass == null) { lock (onlock) { _SingleClass = new SingleClass(); } } return _SingleClass; } } public void BeginConfirmMessageTime() //開啓服務 { while (true) { //天天晚上18這一個小時內檢測執行 if (DateTime.Now.Hour.ToString("18") == "18") { try { //同步數據 Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "我在"+ DateTime.Now + "同步了數據哦!\n"); } catch (Exception ex) { //記錄錯誤日誌(記錄到相應的文件下面) Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\t我是錯誤日誌!" + ex.Message + "\n"); } } Thread.Sleep(1800000); //半個小時執行一次,注意,1000毫秒=1秒,具體須要多少時間能夠自由換算 1800000半小時 } } } } }
1、開發環境
操做系統:Windows 7 X64
開發環境:VS2017
編程語言:C#
.NET版本:.NET Framework 4.6.1
二、引入quartz框架動態連接庫
using Quartz; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MyQuartz { public class TestJob: IJob { public void Execute(IJobExecutionContext context)//指定調用的方法 { try { //在這裏寫代碼(寫本身的業務邏輯) Console.WriteLine("任務執行啦" + DateTime.Now); } catch (Exception ex) { Console.WriteLine("定時任務出錯" + ex.Message); } } } }
四、在Program.cs文件裏面進行調用編寫,編寫內容主要以下:
using Quartz; using Quartz.Impl; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MyQuartz { class Program { static void Main(string[] args) { //1.首先建立一個做業調度池 ISchedulerFactory schedf = new StdSchedulerFactory(); IScheduler sched = schedf.GetScheduler(); //2.建立出來一個具體的做業 IJobDetail job = JobBuilder.Create<TestJob>().Build(); //3.建立並配置一個觸發器 #region(使用SimpleTrigger觸發器,每次3秒執行一次,無上限) ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithSimpleSchedule(x => x.WithIntervalInSeconds(3).WithRepeatCount(int.MaxValue)).Build(); #endregion #region 每3秒執行一次 總共5次 ,開始執行時間設定在當前時間,結束時間我設定在2小時後,不過5次執行完沒2小時候都再也不執行。 //-------NextGivenSecondDate:若是第一個參數爲null則表名當前時間日後推遲2秒的時間點。 //DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddSeconds(5), 2); //DateTimeOffset endTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddHours(2), 3); //ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().StartAt(startTime).EndAt(endTime) // .WithSimpleSchedule(x => x.WithIntervalInSeconds(3).WithRepeatCount(5)) // .Build(); #endregion #region (使用CronTrigger觸發器)在每小時的第10,20,25,26,33,54分鐘,每分鐘的第1,10,14秒執行一次 //DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddSeconds(1), 2); //DateTimeOffset endTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddYears(2), 3); //ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create().StartAt(startTime).EndAt(endTime) // .WithCronSchedule("1,10,59 10,20,21,26,33,54 * * * ? ") // .Build(); #endregion //4.加入做業調度池中 sched.ScheduleJob(job, trigger); //5.開始運行 sched.Start(); Console.ReadKey(); } } }
在上面代碼中能夠看出,咱們主要使用了兩個觸發器:SimpleTrigger觸發器和CronTrigger觸發器;
SimpleTrigger觸發器(簡單觸發器SimpleTrigger)
SimpleTrigger能夠知足的調度需求是:在具體的時間點執行一次,或者在具體的時間點執行,而且以指定的間隔重複執行若干次。好比,你有一個trigger,你能夠設置它在2015年1月13日的上午11:23:54準時觸發,或者在這個時間點觸發,而且每隔2秒觸發一次,一共重複5次。
根據描述,你可能已經發現了,SimpleTrigger的屬性包括:開始時間、結束時間、重複次數以及重複的間隔。這些屬性的含義與你所指望的是一致的,只是關於結束時間有一些地方須要注意。
重複次數,能夠是0、正整數,以及常量SimpleTrigger.REPEAT_INDEFINITELY。重複的間隔,必須是0,或者long型的正數,表示毫秒。注意,若是重複間隔爲0,trigger將會以重複次數併發執行(或者以scheduler能夠處理的近似併發數)。
若是你還不熟悉DateBuilder,瞭解後你會發現使用它能夠很是方便地構造基於開始時間(或終止時間)的調度策略。
endTime屬性的值會覆蓋設置重複次數的屬性值;好比,你能夠建立一個trigger,在終止時間以前每隔10秒執行一次,你不須要去計算在開始時間和終止時間之間的重複次數,只須要設置終止時間並將重複次數設置爲REPEAT_INDEFINITELY(固然,你也能夠將重複次數設置爲一個很大的值,並保證該值比trigger在終止時間以前實際觸發的次數要大便可)。
CronTrigger一般比Simple Trigger更有用,若是您須要基於日曆的概念而不是按照SimpleTrigger的精確指定間隔進行從新啓動的做業啓動計劃。
使用CronTrigger,您能夠指定號時間表,例如「每週五中午」或「每一個工做日和上午9:30」,甚至「每週一至週五上午9:00至10點之間每5分鐘」和1月份的星期五「。
即便如此,和SimpleTrigger同樣,CronTrigger有一個startTime,它指定什麼時候生效,以及一個(可選的)endTime,用於指定什麼時候中止計劃。
Cron Expressions
Cron-Expressions用於配置CronTrigger的實例。Cron Expressions是由七個子表達式組成的字符串,用於描述日程表的各個細節。這些子表達式用空格分隔,並表示: Seconds Minutes Hours Day-of-Month Month Day-of-Week Year (optional field) 一個完整的Cron-Expressions的例子是字符串「0 0 12?* WED「 - 這意味着」每一個星期三下午12:00「。 單個子表達式能夠包含範圍和/或列表。例如,能夠用「MON-FRI」,「MON,WED,FRI」或甚至「MON-WED,SAT」代替前一個(例如「WED」)示例中的星期幾字段。 通配符(' '字符)可用於說明該字段的「每一個」可能的值。所以,前一個例子的「月」字段中的「」字符僅僅是「每月」。所以,「星期幾」字段中的「*」顯然意味着「每週的每一天」。 全部字段都有一組能夠指定的有效值。這些值應該是至關明顯的 - 例如秒和分鐘的數字0到59,數小時的值0到23。日期能夠是1-31的任何值,可是您須要注意在給定的月份中有多少天!月份能夠指定爲0到11之間的值,或者使用字符串JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV和DEC。星期幾能夠指定爲1到7(1 =星期日)之間的值,或者使用字符串SUN,MON,TUE,WED,THU,FRI和SAT。 '/'字符可用於指定值的增量。例如,若是在「分鐘」字段中輸入「0/15」,則表示「每隔15分鐘,從零開始」。若是您在「分鐘」字段中使用「3/20」,則意味着「每隔20分鐘,從三分鐘開始」 - 換句話說,它與「分鐘」中的「3,243,43」相同領域。請注意「 / 35」的細微之處並不表明「每35分鐘」 - 這意味着「每隔35分鐘,從零開始」 - 或者換句話說,與指定「0,35」相同。 '?' 字符是容許的日期和星期幾字段。用於指定「無特定值」。當您須要在兩個字段中的一個字段中指定某個字符而不是另外一個字段時,這頗有用。請參閱下面的示例(和CronTrigger JavaDoc)以進行說明。 「L」字符容許用於月日和星期幾字段。這個角色對於「最後」來講是短暫的,可是在這兩個領域的每個領域都有不一樣的含義。例如,「月」字段中的「L」表示「月的最後一天」 - 1月31日,非閏年2月28日。若是在本週的某一天使用,它只是意味着「7」或「SAT」。可是若是在星期幾的領域中再次使用這個值,就意味着「最後一個月的xxx日」,例如「6L」或「FRIL」都意味着「月的最後一個星期五」。您還能夠指定從該月最後一天的偏移量,例如「L-3」,這意味着日曆月份的第三個到最後一天。當使用'L'選項時,重要的是不要指定列表或值的範圍,由於您會獲得混亂/意外的結果。 「W」用於指定最近給定日期的工做日(星期一至星期五)。例如,若是要將「15W」指定爲月日期字段的值,則意思是:「最近的平日到當月15日」。 '#'用於指定本月的「第n個」XXX工做日。例如,「星期幾」字段中的「6#3」或「FRI#3」的值表示「本月的第三個星期五」。 如下是一些表達式及其含義的更多示例 - 您能夠在JavaDoc中找到更多的org.quartz.CronExpression Cron Expressions示例 CronTrigger示例1 - 建立一個觸發器的表達式,每5分鐘就會觸發一次 「0 0/5 * * *?」 CronTrigger示例2 - 建立觸發器的表達式,每5分鐘觸發一次,分鐘後10秒(即上午10時10分,上午10:05:10等)。 「10 0/5 * * *?」 CronTrigger示例3 - 在每一個星期三和星期五的10:30,11:30,12:30和13:30建立觸發器的表達式。 「0 30 10-13?* WED,FRI「 CronTrigger示例4 - 建立觸發器的表達式,每月5日和20日上午8點至10點之間每半小時觸發一次。請注意,觸發器將不會在上午10點開始,僅在8:00,8:30,9:00和9:30 「0 0/30 8-9 5,20 *?」 請注意,一些調度要求太複雜,沒法用單一觸發表示 - 例如「每上午9:00至10:00之間每5分鐘,下午1:00至晚上10點之間每20分鐘」一次。在這種狀況下的解決方案是簡單地建立兩個觸發器,並註冊它們來運行相同的做業。
具體使用方法見CronTrigger觸發器使用規則:https://www.w3cschool.cn/quartz_doc/quartz_doc-lwuv2d2a.html
執行演示
寫完後咱們查看執行結果,我使用的是SimpleTrigger觸發器,每3秒執行一次,無上限,各位能夠根據自身的項目需求更改使用不一樣的觸發器
注意:
若是定時任務框架quartz這個掛在iis上會被回收掉(默認是20分鐘)
Quartz高版本的存在兼容性,建議使用低版本的(2.5.0)
總結
到這裏Windows Service服務和定時任務框架quartz都簡單的介紹完了,具體使用哪個或者配套使用就看自己項目邏輯了;
如今執行的邏輯:
Windows Service服務:程序隨電腦開機啓動,每隔半個小時執行一次,檢測到執行時間等於我設置的時間就去執行後臺邏輯;
定時任務框架quartz:若是發佈在iis上,默認20分鐘後會被回收(程序不能一直等待執行),程序處於休眠狀態,到指定時候後喚醒(觸發器)程序執行後臺邏輯;
PS:若是把quartz結合windows服務使用的話就不存在被回收問題;
![]()
歡迎關注訂閱個人微信公衆平臺【熊澤有話說】,更多好玩易學知識等你來取
做者:熊澤-學習中的苦與樂 公衆號:熊澤有話說 出處: https://www.cnblogs.com/xiongze520/p/13031944.html 創做不易,任何人或團體、機構所有轉載或者部分轉載、摘錄,請在文章明顯位置註明做者和原文連接。 |