zoukankan      html  css  js  c++  java
  • 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我们还在继续研究的路上!

    回到目录

  • 相关阅读:
    用Python完成Excel的常用操作
    用Python实现excel 14个常用操作
    ubuntu and centos各种上网代理设置
    vim 熟练度练习
    Ansible-playbook 使用方式 看一篇就够了
    python 使用ldap3 查询跨域的用户信息
    python pyinstaller 的使用
    vs code新建python虚拟环境
    vs code 远程开发环境设置
    上下文管理器(Context Manager)
  • 原文地址:https://www.cnblogs.com/lori/p/7525467.html
Copyright © 2011-2022 走看看