回到目录html
以前写过一篇文件《DotNetCore跨平台~Quartz热部署的福音~监控文件夹的变化》,今天主要把框架优化了一下,支持外部触发,并支持外部将参数以JobDataMap形式进行输入,而后在我们的Job里进行使用它,故称参数化任务。框架
Quartz使用场景:post
今天说的外部触发的任务是指第一种,即在将来某个时间点去执行,而且只执行一次。说一下思路,这种任务某个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咱们还在继续研究的路上!