日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

无需Get更多技能,快速打造一个可持久化的任务调度

發(fā)布時(shí)間:2025/4/14 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 无需Get更多技能,快速打造一个可持久化的任务调度 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

    項(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)。

1 public interface IAutoService 2 { 3 /// <summary> 4 /// 服務(wù)名稱 5 /// </summary> 6 string ServiceName { get; } 7 8 /// <summary> 9 /// 啟動(dòng)方法 10 /// </summary> 11 void Start(); 12 13 /// <summary> 14 /// 是否啟用 15 /// </summary> 16 bool IsEnable { get; } 17 }
  • AutoServiceBase: 抽象類實(shí)現(xiàn)接口原則,規(guī)范自動(dòng)任務(wù)的可選參數(shù),統(tǒng)一封裝調(diào)用,定義抽象方法與屬性,子類重寫。

1 public abstract class AutoServiceBase : IAutoService 2 { 3 public IQuartzConfiguration QuartzConfiguration { get; set; } 4 5 public IQuartzScheduleJobManager QuartzScheduleJobManager { get; set; } 6 7 public const string ServiceGroupName = "AutoService.Groups"; 8 9 /// <summary> 10 /// 服務(wù)名稱 11 /// </summary> 12 public virtual string ServiceName { get { return "服務(wù)啟動(dòng)..."; } } 13 14 /// <summary> 15 /// 任務(wù)調(diào)度 16 /// </summary> 17 public virtual Action<TriggerBuilder> ConfigureTrigger { get; } 18 19 public virtual bool IsEnable { get { return true; } } 20 21 /// <summary> 22 /// 獲取服務(wù)方法名稱 23 /// </summary> 24 /// <returns></returns> 25 public abstract string GetServiceIdentiy(); 26 27 /// <summary> 28 /// 啟動(dòng)任務(wù) 29 /// </summary> 30 public abstract void Start(); 31 32 }

定義好基礎(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等

1 public interface IQuartzScheduleJobManager 2 { 3 /// <summary> 4 /// 增加任務(wù)與任務(wù)調(diào)度到任務(wù)工廠 5 /// </summary> 6 /// <typeparam name="TJob"></typeparam> 7 /// <param name="configureJob">任務(wù)</param> 8 /// <param name="configureTrigger">任務(wù)調(diào)度</param> 9 /// <returns></returns> 10 Task ScheduleAsync<TJob>(Action<JobBuilder> configureJob, Action<TriggerBuilder> configureTrigger) where TJob : IJob; 11 12 /// <summary> 13 /// 啟動(dòng)任務(wù) 14 /// </summary> 15 void Start(); 16 17 /// <summary> 18 /// 等待任務(wù)完成并停止任務(wù) 19 /// </summary> 20 void ShutDown(); 21 } 22 23 public class QuartzScheduleJobManager : IQuartzScheduleJobManager 24 { 25 private readonly IQuartzConfiguration _quartzConfiguration; 26 27 public QuartzScheduleJobManager( 28 IQuartzConfiguration quartzConfiguration) 29 { 30 _quartzConfiguration = quartzConfiguration; 31 } 32 33 /// <summary> 34 /// 增加任務(wù)與任務(wù)調(diào)度到任務(wù)工廠 35 /// </summary> 36 /// <typeparam name="TJob"></typeparam> 37 /// <param name="configureJob">任務(wù)</param> 38 /// <param name="configureTrigger">任務(wù)調(diào)度</param> 39 /// <returns></returns> 40 public Task ScheduleAsync<TJob>(Action<JobBuilder> configureJob, Action<TriggerBuilder> configureTrigger) 41 where TJob : IJob 42 { 43 var jobToBuild = JobBuilder.Create<TJob>(); 44 configureJob(jobToBuild); 45 var job = jobToBuild.Build(); 46 47 var triggerToBuild = TriggerBuilder.Create(); 48 configureTrigger(triggerToBuild); 49 var trigger = triggerToBuild.Build(); 50 51 _quartzConfiguration.Scheduler.ScheduleJob(job, trigger); 52 53 return Task.FromResult(0); 54 } 55 56 /// <summary> 57 /// 啟動(dòng)任務(wù) 58 /// </summary> 59 public void Start() 60 { 61 //啟動(dòng)任務(wù)調(diào)度框架 62 if (!_quartzConfiguration.Scheduler.IsStarted) 63 { 64 _quartzConfiguration.Scheduler.Start(); 65 } 66 } 67 68 /// <summary> 69 /// 等待任務(wù)完成并停止任務(wù) 70 /// </summary> 71 public void ShutDown() 72 { 73 if (_quartzConfiguration.Scheduler.IsStarted && !_quartzConfiguration.Scheduler.IsShutdown) 74 { 75 _quartzConfiguration.Scheduler.Shutdown(); 76 } 77 } 78 }

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è)方法體:

  • JobExecutionVetoed
  • JobToBeExecuted
  • JobWasExecuted
  • 查看字面意思,我們就能很好理解就是對(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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。