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

回到目錄html

以前寫過一篇文件《DotNetCore跨平臺~Quartz熱部署的福音~監控文件夾的變化》,今天主要把框架優化了一下,支持外部觸發,並支持外部將參數以JobDataMap形式進行輸入,而後在我們的Job裏進行使用它,故稱參數化任務。框架

Quartz使用場景:post

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

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

用例:你能夠在quartz調度中內心對外公開一些方法,讓你的Job依賴於某個時間點和參數去執行,執行一次就中止,這樣咱們的調度就更加靈活了。ui

爲單次任務添加了IsSingle屬性this

    [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隊列的方法spa

在咱們以前的QuartzManager管理者中,咱們須要添加對單次任務的支持,這點咱們將任務加入到quartz的代碼進行了重構,提取到了方法裏。code

        /// <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);
            }
        }

對外公開的參數化接口htm

而對於外界若是但願再次觸發這個單次任務,咱們能夠在QuartzManager裏公開一個方法,用來向當前SchedulerFactory裏添加新的Job就能夠了,這個方法很簡單,能夠提供一個默認的時間策略,如默認爲1分鐘後執行,也能夠本身控制時間。blog

      /// <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咱們還在繼續研究的路上!

回到目錄

相關文章
相關標籤/搜索