1. 程式人生 > >DotNetCore跨平臺~Quartz定時單次任務

DotNetCore跨平臺~Quartz定時單次任務

回到目錄

之前寫過一篇檔案《DotNetCore跨平臺~Quartz熱部署的福音~監控資料夾的變化》,今天主要把框架優化了一下,支援外部觸發,並支援外部將引數以JobDataMap形式進行輸入,然後在咱們的Job裡進行使用它,故稱引數化任務。

Quartz使用場景:

  1. 定時單次任務:在未來某個時間去執行一次
  2. 定點任務  :在某個時間去執行,可以是輪詢的
  3. 週期任務  :按某個時間間隔去輪詢執行

今天說的外部觸發的任務是指第一種,即在未來某個時間點去執行,並且只執行一次。說一下思路,這種任務某個JobBase的子類,它需要重寫屬性IsSingle,將值設為1表示單次任務,然後在Quartz啟動後,它會被立即執行,執行完成後,銷燬!

用例:你可以在quartz排程中心裡對外公開一些方法,讓你的Job依賴於某個時間點和引數去執行,執行一次就停止,這樣我們的排程就更加靈活了。

為單次任務添加了IsSingle屬性

    [DisallowConcurrentExecution()]
    public abstract class JobBase : ISchedulingJob
    {
        #region Properties

        /// <summary>
        /// 取消資源
        /// </summary>
        public
CancellationTokenSource CancellationSource => new CancellationTokenSource(); /// <summary> /// 執行計劃,除了立即執行的JOB之後,其它JOB需要實現它 /// </summary> public virtual string Cron => "* * * * * ?"; /// <summary> /// 是否為單次任務,黑為false /// </summary>
public virtual bool IsSingle => false; /// <summary> /// Job的名稱,預設為當前類名 /// </summary> public virtual string JobName => GetType().Name; /// <summary> /// Job執行的超時時間(毫秒),預設5分鐘 /// </summary> public virtual int JobTimeout => 5 * 60 * 1000; #endregion Properties #region Methods /// <summary> /// Job具體類去實現自己的邏輯 /// </summary> protected abstract void ExcuteJob(IJobExecutionContext context, CancellationTokenSource cancellationSource); /// <summary> /// 當某個job超時時,它將被觸發,可以發一些通知郵件等 /// </summary> /// <param name="arg"></param> private void CancelOperation(object arg) { CancellationSource.Cancel(); StdSchedulerFactory.GetDefaultScheduler().Result.Interrupt(new JobKey(JobName)); Console.WriteLine(JobName + "Job執行超時,已經取消,等待下次排程..."); } #endregion Methods #region IJob 成員 public Task Execute(IJobExecutionContext context) { Timer timer = null; try { timer = new Timer(CancelOperation, null, JobTimeout, Timeout.Infinite); Console.WriteLine(DateTime.Now.ToString() + "{0}這個Job開始執行", context.JobDetail.Key.Name); if (context.JobDetail.JobDataMap != null) { foreach (var pa in context.JobDetail.JobDataMap) Console.WriteLine($"JobDataMap,key:{pa.Key},value:{pa.Value}"); } ExcuteJob(context, CancellationSource); } catch (Exception ex) { Console.WriteLine(this.GetType().Name + "error:" + ex.Message); } finally { if (timer != null) timer.Dispose(); } return Task.CompletedTask; } #endregion }

統一的加入Job佇列的方法

在我們之前的QuartzManager管理者中,我們需要新增對單次任務的支援,這點我們將任務加入到quartz的程式碼進行了重構,提取到了方法裡。

        /// <summary>
        /// 將型別新增到Job佇列
        /// </summary>
        /// <param name="type">型別</param>
        /// <param name="dt">時間點</param>
        /// <param name="param">引數</param>
        private static void JoinToQuartz(Type type, DateTimeOffset dt, Dictionary<string, object> param = null)
        {
            var obj = Activator.CreateInstance(type);
            if (obj is ISchedulingJob)
            {
                var tmp = obj as ISchedulingJob;
                string cron = tmp.Cron;
                string name = tmp.JobName;
                var cancel = tmp.CancellationSource;

                var jobDetail = JobBuilder.Create(type)
                                          .WithIdentity(name)
                                          .Build();
                if (param != null)
                    foreach (var dic in param)
                        jobDetail.JobDataMap.Add(dic.Key, dic.Value);

                ITrigger jobTrigger;
                if (tmp.IsSingle)
                {
                    jobTrigger = TriggerBuilder.Create()
                                               .WithIdentity(name + "Trigger")
                                               .StartAt(dt)
                                               .Build();
                }
                else
                {
                    jobTrigger = TriggerBuilder.Create()
                                                .WithIdentity(name + "Trigger")
                                                .StartNow()
                                                .WithCronSchedule(cron)
                                                .Build();
                }
                StdSchedulerFactory.GetDefaultScheduler().Result.ScheduleJob(jobDetail, jobTrigger, cancel.Token);
                LoggerInfo($"->任務模組{name}被裝載...", ConsoleColor.Yellow);
            }
        }

對外公開的引數化介面

而對於外界如果希望再次觸發這個單次任務,我們可以在QuartzManager裡公開一個方法,用來向當前SchedulerFactory裡新增新的Job就可以了,這個方法很簡單,可以提供一個預設的時間策略,如預設為1分鐘後執行,也可以自己控制時間。

      /// <summary>
        /// 任務在1分鐘之後被執行1次
        /// </summary>
        /// <param name="type"></param>
        /// <param name="job"></param>
        /// <param name="param"></param>
        public static void SignalJob(Type type, Dictionary<string, object> param)
        {
            SignalJob(type, DateTimeOffset.Now.AddSeconds(10), param);
        }

        /// <summary>
        /// 任務在某個時間之後被執行1次
        /// </summary>
        /// <param name="type"></param>
        /// <param name="job"></param>
        /// <param name="offset"></param>
        /// <param name="param"></param>
        public static void SignalJob(Type type, DateTimeOffset offset, Dictionary<string, object> param)
        {
            JoinToQuartz(type, offset);
        }

那麼,現在某個任務排程中心就更加完善了,開發人員在使用時也很簡單,只要繼承JobBase,或者去實現ISchedulingJob介面就可以了,非常靈活!

感謝各位的閱讀!

quartz,dotnet core我們還在繼續研究的路上!

回到目錄