无需Get更多技能,快速打造一个可持久化的任务调度
項(xiàng)目總是很忙,忙里偷閑還是要總結(jié)一下,前一段時(shí)間,由于項(xiàng)目中需要,我們需要很多定時(shí)匯總數(shù)據(jù)的情況,項(xiàng)目初期主要使用sql server 計(jì)劃任務(wù)實(shí)現(xiàn)對(duì)數(shù)據(jù)的匯總與統(tǒng)計(jì),但是開發(fā)到一定時(shí)間內(nèi),需求提出了很多自動(dòng)任務(wù)的功能,很多不是能夠在SQL Server中進(jìn)行解決的,例如訂單關(guān)閉前多少分鐘內(nèi)發(fā)短信與郵箱告訴用戶,程序?qū)用婷刻靺R總錯(cuò)誤日志發(fā)送至運(yùn)維郵箱等,針對(duì)目前情況,簡(jiǎn)單上網(wǎng)查了一下,決定使用TopShelf + Quartz 進(jìn)行自動(dòng)服務(wù)與任務(wù)調(diào)度,關(guān)于這兩項(xiàng)的介紹也很多了,廢話不多說,直接上代碼:
-
項(xiàng)目結(jié)構(gòu)圖如下:
?
任務(wù)調(diào)度與任務(wù)實(shí)現(xiàn)實(shí)質(zhì)是兩個(gè)完全不同的東西,所以自動(dòng)服務(wù)于Job執(zhí)行是應(yīng)該分開的,所以任務(wù)創(chuàng)建時(shí)應(yīng)該吧Job加載到任務(wù)調(diào)度工程,最后告訴調(diào)度工廠,可以開始執(zhí)行任務(wù)之后,調(diào)度工廠會(huì)進(jìn)行掃描Job,加載到內(nèi)存中挨個(gè)執(zhí)行。
-
IAutoService:?主要是聲明自動(dòng)服務(wù)的接口模式,標(biāo)記了服務(wù)的名稱,啟動(dòng)時(shí)的加載等,統(tǒng)一由抽象類AutoServcieBase實(shí)現(xiàn)。
-
AutoServiceBase: 抽象類實(shí)現(xiàn)接口原則,規(guī)范自動(dòng)任務(wù)的可選參數(shù),統(tǒng)一封裝調(diào)用,定義抽象方法與屬性,子類重寫。
定義好基礎(chǔ)服務(wù)后,接下來我們就要使用TopShelf搭建一個(gè)屬于我們自己的windows service了,代碼如下:
class Program{static void Main(string[] args){HostFactory.Run(x =>{x.Service<Service>(s =>{s.ConstructUsing(name => new Service());s.WhenStarted(tc => tc.Start());s.WhenStopped(tc => tc.Stop());s.WhenShutdown(tc => tc.Shutdown());});x.RunAsLocalSystem();x.SetDescription("服務(wù)集合,包含自動(dòng)化消息,響應(yīng)隊(duì)列的領(lǐng)域事件");x.SetDisplayName("Test.Services");x.SetServiceName("Test.Services");});}}??topshelf是一個(gè)很簡(jiǎn)單就能創(chuàng)建service的工具,它開源在GitHub TopShelf上,是一款快速搭建mono與windows service ,在編寫好我們的服務(wù)代碼,只需簡(jiǎn)單地啟動(dòng)代碼,就能創(chuàng)建一個(gè)持久化的服務(wù),不過想要兼容在Mono上也是非常簡(jiǎn)單,只需加入如下一句代碼即可。
x.UseLinuxIfAvailable();?在我們的項(xiàng)目中windows service不僅僅是任務(wù)調(diào)度的寄宿形式,同時(shí)也是我們Event Store,對(duì)DDD感興趣的同學(xué)可以了解CQRS中SAGA模式中事件消費(fèi)的形式,這個(gè)不在本文討論。
創(chuàng)建好我們的基礎(chǔ)服務(wù)后,接下來就是對(duì)任務(wù)調(diào)度工廠的設(shè)置,任務(wù)調(diào)度簡(jiǎn)單來看,我們往往要使用事件監(jiān)聽,任務(wù)總調(diào)度工廠等等,這里Quartz很好的集成了這些,我們只需進(jìn)行簡(jiǎn)單的改造就能夠?qū)崿F(xiàn)如上功能。
-
QuartzScheduleJobManager:實(shí)現(xiàn)任務(wù)調(diào)度管理,在這里可以對(duì)總?cè)蝿?wù)調(diào)度工廠進(jìn)行啟動(dòng),停止,加載Job等
IQuartzConfiguration是對(duì)IScheduler的一個(gè)簡(jiǎn)單封裝,創(chuàng)建默認(rèn)的調(diào)度程序:
1 public class QuartzConfiguration : IQuartzConfiguration 2 { 3 public IScheduler Scheduler => StdSchedulerFactory.GetDefaultScheduler(); 4 }?接下來就是任務(wù)監(jiān)聽,Quartz提供了一個(gè)很好的擴(kuò)展,我們只需實(shí)現(xiàn)IJobListener接口即可,包含如下多個(gè)方法體:
查看字面意思,我們就能很好理解就是對(duì)每一個(gè)job在執(zhí)行中的階段所對(duì)應(yīng)的事件,方法體內(nèi)給出IJobExecutionContext當(dāng)前執(zhí)行的上下文,通過上下文我們可以輸出許多我們想要的東西,例如當(dāng)前執(zhí)行Job的Name,執(zhí)行時(shí)間,等等,也提供了JobExecutionException等異常信息,可以監(jiān)控Job執(zhí)行過程中發(fā)生的錯(cuò)誤,很方便。
好了在我們的寄宿服務(wù),與基礎(chǔ)服務(wù)搭建完畢后,接下來就是要實(shí)現(xiàn)在業(yè)務(wù)系統(tǒng)中我們自身的邏輯結(jié)構(gòu)了,核心程序類Servcie.cs,在service中我們需要將我們?nèi)缟系呐渲眠M(jìn)行加載,并同時(shí)掃描我們業(yè)務(wù)系統(tǒng)中的定時(shí)服務(wù)類,挨個(gè)進(jìn)行啟動(dòng),代碼如下:
?
public class Service{/// <summary>/// 任務(wù)調(diào)度框架/// </summary>private IQuartzScheduleJobManager QuartzScheduleJobManager{get{return IocManager.Instance.Resolve<IQuartzScheduleJobManager>();}}/// <summary>/// 任務(wù)調(diào)度配置/// </summary>public IQuartzConfiguration QuartzConfiguration{get{return IocManager.Instance.Resolve<IQuartzConfiguration>();}}public Service(){try{//注冊(cè)我們的任務(wù)調(diào)度程序配置
IocManager.Register<IQuartzConfiguration, QuartzConfiguration>();
//注冊(cè)任務(wù)監(jiān)聽程序到Ioc
?IocManager.Register<IJobListener, QuartzJobListener>();
//聲明一個(gè)接口可以被多個(gè)實(shí)例實(shí)現(xiàn)IocManager.IocContainer.Kernel.Resolver.AddSubResolver(new ArrayResolver(TongTongMallBootstrapper.IocManager.IocContainer.Kernel, true));}catch (Exception ex){LogHelper.LogException(ex);}}
//設(shè)置我們的配置項(xiàng)public void QuartzConfigurationInitialize(){//Job映射工廠QuartzConfiguration.Scheduler.JobFactory = new QuartzJobFactory(IocManager.Instance);//Job 監(jiān)聽配置QuartzConfiguration.Scheduler.ListenerManager.AddJobListener(IocManager.Instance.Resolve<IJobListener>());}/// <summary>/// 基礎(chǔ)類服務(wù)/// </summary>public void Start(){//訂閱各項(xiàng)自動(dòng)服務(wù)IocManager.Instance.IocContainer.Register(Classes.FromThisAssembly().BasedOn<IAutoService>().WithService.Base()); QuartzConfigurationInitialize();RegisterService();}/// <summary>/// 停止自動(dòng)服務(wù)/// </summary>public void Stop(){QuartzScheduleJobManager.ShutDown();}/// <summary>/// 結(jié)束自動(dòng)服務(wù)/// </summary>public void Shutdown(){TongTongMallBootstrapper.Dispose();QuartzScheduleJobManager.ShutDown();}/// <summary>/// 注冊(cè)服務(wù)/// </summary>/// <param name="args"></param>public void RegisterService(){foreach (var service in IocManager.Instance.IocContainer.ResolveAll<IAutoService>()){if (service.IsEnable){LogHelper.Logger.Debug($"{service.ServiceName}服務(wù)正在啟動(dòng)中...");service.Start();}}LogHelper.Logger.Debug($"任務(wù)總調(diào)度工廠啟動(dòng)!");QuartzScheduleJobManager.Start();}}
?在系統(tǒng)中我們主要使用了IOC進(jìn)行了一個(gè)服務(wù)的自動(dòng)掃描與切入,在服務(wù)配置完畢后,接下來我們只需定義業(yè)務(wù)相關(guān)的自動(dòng)服務(wù)即可,通過繼承我們的抽象類AutoServiceBase,接下來就很方便的打造每一個(gè)自動(dòng)任務(wù)調(diào)度了,而關(guān)于Quartz的任務(wù)調(diào)度形式與時(shí)間配置,不是本文的重點(diǎn)介紹內(nèi)容,就不在詳說,不過在任務(wù)調(diào)度中我們也可以實(shí)現(xiàn)很多自定義的時(shí)間調(diào)度模式,例如自定義的節(jié)假日,或者每周一執(zhí)行任務(wù)調(diào)度都可以,這個(gè)需要進(jìn)行進(jìn)一步編碼實(shí)現(xiàn)。
由于公司方面,代碼就不在給連接資源下載了,代碼給出只是思路,當(dāng)然在這里面還可以有更多的擴(kuò)展,而本文只是方便快速上手為第一原則,文章有寫的不當(dāng)?shù)牡胤?#xff0c;請(qǐng)及時(shí)指出,如本文對(duì)您有所幫助,也請(qǐng)點(diǎn)個(gè)推薦,您的肯定也是是我最大的動(dòng)力。thanks
轉(zhuǎn)載于:https://www.cnblogs.com/doNetTom/p/6442201.html
總結(jié)
以上是生活随笔為你收集整理的无需Get更多技能,快速打造一个可持久化的任务调度的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hibernate查询-基本查询
- 下一篇: 让字体图标代替雪碧图,减少请求带宽