DotNetCore跨平(ping)臺(tai)~Quartz熱部署的福(fu)音~監控文件夾的變(bian)化
在DotNetCore出來之后,同(tong)時也使(shi)用(yong)了quartz進行(xing)調度(du)中心(xin)的(de)(de)設計,將它做到docker里方(fang)便部署,在之前的(de)(de)quartz版本里支持配(pei)置文(wen)(wen)件的(de)(de)方(fang)式,而現在不(bu)(bu)支持了,我(wo)們應該去想一下(xia),為什么不(bu)(bu)去支持配(pei)置文(wen)(wen)件?當然(ran)大叔也為配(pei)置文(wen)(wen)件設計了支持的(de)(de)方(fang)式,但我(wo)們還(huan)是應該想想作者為什么不(bu)(bu)去支持配(pei)置?
熱插拔(ba),服務發(fa)現?
和上面(mian)兩個(ge)概念可能(neng)(neng)有點(dian)關系,熱插拔很(hen)容易(yi)理(li)解(jie),就是(shi)(shi)把dll模塊放到正在運(yun)行的(de)(de)(de)項目時,它(ta)(ta)可以直接啟(qi)動(dong),這個(ge)功(gong)能(neng)(neng)對調度中心(xin)來說(shuo),很(hen)是(shi)(shi)必(bi)要(yao)(yao),因為(wei)你可能(neng)(neng)需要(yao)(yao)按著不(bu)同(tong)的(de)(de)(de)功(gong)能(neng)(neng)設計一些(xie)服務(wu)job,而(er)(er)這些(xie)服務(wu)沒有什么聯系,每個(ge)job功(gong)能(neng)(neng)單一,如果(guo)做成熱部(bu)署,挺好!而(er)(er)服務(wu)發(fa)(fa)(fa)現在最近<微服務(wu)>里很(hen)是(shi)(shi)槍(qiang)眼,今天說(shuo)的(de)(de)(de)服務(wu)發(fa)(fa)(fa)現并不(bu)是(shi)(shi)它(ta)(ta),而(er)(er)是(shi)(shi)dotnet core公開的(de)(de)(de)對文件(jian)(jian)夾(jia)的(de)(de)(de)監控,其實(shi)就是(shi)(shi)一種(zhong)事件(jian)(jian)機(ji)制(zhi),當windows底層文件(jian)(jian)夾(jia)改(gai)變時(增,刪,改(gai)文件(jian)(jian)),會(hui)向上觸發(fa)(fa)(fa)對應的(de)(de)(de)事件(jian)(jian),而(er)(er)我們只要(yao)(yao)去訂閱它(ta)(ta)即(ji)可,非常的(de)(de)(de)松耦合(he)!
公開(kai)的事件
var watcher = new FileSystemWatcher(); watcher.Path = AppDomain.CurrentDomain.BaseDirectory; watcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size; watcher.Filter = "*.dll"; // quartz運(yun)行時,可以添(tian)加新job,但不能覆蓋(gai),刪除等 watcher.Created += new FileSystemEventHandler((o, e) => { foreach (var module in Assembly.LoadFile(e.FullPath).GetModules()) { foreach (var type in module.GetTypes().Where(i => i.BaseType == typeof(JobBase))) { JoinToQuartz(type); } } }); //Start monitoring. watcher.EnableRaisingEvents = true;
將job添加(jia)到(dao)Quartz需(xu)要在(zai)初(chu)始(shi)化和(he)文件夾監(jian)控兩個(ge)地方用(yong)到(dao),所以(yi)我(wo)們(men)進行了抽象,把(ba)它(ta)提到(dao)一個(ge)委托(tuo)里,使用(yong).net4.0的Actioin<T>委托(tuo)來實(shi)現(xian)最為合適了!
Action<Type> JoinToQuartz = (type) => { var obj = Activator.CreateInstance(type); string cron = type.GetProperty("Cron").GetValue(obj).ToString(); var jobDetail = JobBuilder.Create(type) .WithIdentity(type.Name) .Build(); var jobTrigger = TriggerBuilder.Create() .WithIdentity(type.Name + "Trigger") .StartNow() .WithCronSchedule(cron) .Build(); StdSchedulerFactory.GetDefaultScheduler().Result.ScheduleJob(jobDetail, jobTrigger); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"新添加了一(yi)個服務{nameof(type)},通過心(xin)跳Job自動被加載!"); };
大叔把它應用到了調度中心上,具體就是當調試項目里有新的模塊DLL出現后,自動將它添加到quartz的列表里,然后當然它有自己的cron表達式去控制自己的調度周期,你是定點地還是周期運行完成由自己的job去控制,如果有新功能,就加新Job,是否有點單一職(zhi)責和開閉(bi)原則(ze)的(de)意思!
JobBase,所有模塊的功能Job都要繼承它,可以根據自己的情況,實現cron和業務ExcuteJob方法!
[DisallowConcurrentExecution()] public abstract class JobBase : IJob { #region IJob 成員 public Task Execute(IJobExecutionContext context) { try { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(DateTime.Now.ToString() + "{0}這個Job開始執行", context.JobDetail.Key.Name); ExcuteJob(context); return Task.CompletedTask; ; } catch (Exception ex) { LoggerFactory.CreateLog().Logger_Debug(this.GetType().Name + "error:" + ex.Message); throw; } } #endregion /// <summary> /// 執行計劃,子類(lei)可以重寫(xie) /// </summary> public virtual string Cron => "0/5 * * * * ?"; /// <summary> /// Job具體類去實(shi)現自己的邏輯 /// </summary> protected abstract void ExcuteJob(IJobExecutionContext context); }
下面看其中(zhong)一個(ge)業務(wu)Job的實現,它主要由調度計劃cron和業務(wu)執(zhi)行方法ExcuteJob組(zu)成
/// <summary> /// 發送消息(xi) /// </summary> public class SendEmailJob : JobBase { public override string Cron => "0/2 * * * * ?"; protected override void ExcuteJob(IJobExecutionContext context) { Console.WriteLine("發送Email"); LoggerFactory.CreateLog().Logger_Debug("發送Email:" + DateTime.Now); } }
當(dang)我們把(ba)這個項目發布到dotnet core之(zhi)后(hou),可以設計(ji)一個web api /web mvc管理UI,然(ran)后(hou)去查看和管理自己的任務,現在quartz2.x里的crystal管理工具已經用(yong)不了了,所以咱們還(huan)是DIY一下吧(ba)!哈(ha)(ha)哈(ha)(ha)!

可以查看(kan)任務列表,管理它們的(de)啟動(dong)與停(ting)止的(de)狀態(tai)!
感謝各位的閱讀!