zoukankan      html  css  js  c++  java
  • 任务调度

    一个任务调度

     

    最近把以前项目中用的任务调度提了出来,做了一个Demo。

     

    任务调度用到的组件是quartz.net。关于quartz.net的文章网上有很多了,这里再简单介绍下。

    首先是创建一个作业明细

     View Code

    然后是创建一个触发器

     View Code

    最后把创建的两样组合起来就新增了一个作业了

     View Code

    作业必须实现IJob接口

    这里用了一个基类来实现IJob接口,基类里有一个抽象方法,其他作业子类只要继承这个基类并实现这个抽象方法就行了。

    复制代码
    public void Execute(IJobExecutionContext context)
            {
                //Quartz.Collection.ISet<JobKey> jobKeys = context.Scheduler.GetJobKeys(
                //      Quartz.Impl.Matchers.GroupMatcher<JobKey>.GroupEquals(JobHelp.jobGroupName));    //取所有运行的作业
    
                var task = context.MergedJobDataMap["task"] as ScheduleTask;
                string message = string.Format("{0}的『Execute』从『IJobExecutionContext』读取不到作业计划!", ""); // this.FullDevName
                if (task == null) throw new Exception(message);
    
                //刷新作业计划信息,防止作业计划配置发生改变
                string sql = "select * from ScheduleTask where id=@id";
                var taskNew = _scheduleTask.GetFirst<ScheduleTask>(sql, new { id = task.Id });
    
                if (taskNew == null)
                {
                    //计划已经被删除,则删除此作业
                    context.Scheduler.DeleteJob(context.JobDetail.Key);
                    Log.Logger.InfoFormat(string.Format("{0}作业计划为空,该记录可能已经被删除。", taskNew.MethodName));
                    return; //退出
                }
    
                //作业不允许使用
                if (!taskNew.Allowused)
                {
                    //不从调度计划中删除本作业,因为有可能又启用该作业计划
                    Log.Logger.InfoFormat(string.Format("{0}作业计划不允许使用,跳过此次执行。", taskNew.MethodName));
                    return; //退出
                }
                if (taskNew != task)
                {
    
                    //脏数据,删除此作业,然后重新创建一个
                    Log.Logger.InfoFormat("{0}的作业计划属性已更改,将删除该计划的实现作业,然后重新创建一个作业,并尝试调度它...", taskNew.MethodName);
                    //作业计划属性发生变更,重新启动作业
                    Tuple<IJobDetail, ITrigger> tuple = JobHelp.RestartJob(context.Scheduler, task, taskNew);
                    Log.Logger.InfoFormat("{0}重新创建并调度作业完成,『IJOB.Execute』退出。作业计划:{1},作业:{2},触发器:{3},表达式:{4}。", taskNew.MethodName, taskNew.MethodName, tuple.Item1.Key.Name, tuple.Item2.Key.Name, taskNew.CronExpression);
                    return; //退出
                }
                
                //执行具体作业的业务逻辑
                ExecuteJobImpl(context);
    
                //更新执行时间
                taskNew.LastTime=DateTime.Now.ToString();
                taskNew.NextTime = string.Format("{0:G}", context.NextFireTimeUtc.Value.AddHours(8));
                UpdateTime(taskNew);
            }
    复制代码

    新增作业

    怎样新增一个作业呢?

    新增一个作业也很简单,只需在TaskManageDemo.Task项目下添加一个类,并继承作业父类实现抽象方法就可以了。

    那怎样来配置呢?

    实现了作业后,点击新增按钮来增加一个作业。

    新增的作业是怎样被触发的呢?  

    这里我用了一个系统作业来唤醒新增的作业和删除不需要的作业。

    复制代码
    protected override void ExecuteJobImpl(Quartz.IJobExecutionContext context)
            {
                //取所有运行的作业
                Quartz.Collection.ISet<JobKey> jobKeys = context.Scheduler.GetJobKeys(
                       Quartz.Impl.Matchers.GroupMatcher<JobKey>.GroupEquals(JobHelp.jobGroupName));
    
                string sql = "select * from ScheduleTask where ClassName!=@ClassName";
                var taskRuning = new List<ScheduleTask>();//正在运行的作业
                var taskInDb = _scheduleTask.Query<ScheduleTask>(sql, new { ClassName = "SysJob" }); //存在于数据库的作业,不包括系统作业
                foreach (var jk in jobKeys)
                {
                    IJobDetail job = context.Scheduler.GetJobDetail(jk);
                    ScheduleTask task = job.JobDataMap["task"] as ScheduleTask;
                    if (task == null || task.ClassName == "SysJob") continue;  //不检查系统作业  
    
                    //在数据库检测一次
                    var taskInDb2 = taskInDb.ToList().FirstOrDefault(a => a.Id == task.Id);
                    if (taskInDb2 == null)
                    {
                        context.Scheduler.DeleteJob(jk); //删除该作业
                        Log.Logger.InfoFormat("作业计划『{0}』已经不存在于数据库。", task.ClassName);
                        continue;
                    }
                    taskRuning.Add(taskInDb2);
    
                    if (taskInDb2 != task)
                    {
    
                        //脏数据,删除此作业,然后重新创建一个
                        Log.Logger.InfoFormat("{0}的作业计划属性已更改,将删除该计划的实现作业,然后重新创建一个作业,并尝试调度它...", taskInDb2.ClassName);
                        //作业计划属性发生变更,重新启动作业
                        Tuple<IJobDetail, ITrigger> tuple = JobHelp.RestartJob(context.Scheduler, task, taskInDb2);
                        Log.Logger.InfoFormat("{0}重新创建并调度作业完成,『IJOB.Execute』退出。作业计划:{1},作业:{2},触发器:{3},表达式:{4}。", taskInDb2.ClassName, taskInDb2.ClassName, tuple.Item1.Key.Name, tuple.Item2.Key.Name, taskInDb2.CronExpression);
                        return; //退出
                    }
                }
                //过滤出新增的作业
                var newTask = taskInDb.Except(taskRuning);
                if (newTask.Count() > 0)
                {
                    //动态增加作业
                    Log.Logger.InfoFormat("系统作业检测到有{0}个新增作业计划,开始创建这些作业...", newTask.Count());
                    foreach (var task in newTask)
                        TaskManageDemo.Utility.Common.Execute(ScheduleJobByPlan, context.Scheduler, task, "创建作业失败,作业计划名称:{0}", task.ClassName); 
    
                    Log.Logger.InfoFormat("系统作业创建作业完毕,共创建{0}个作业。", context.Scheduler.GetJobKeys(Quartz.Impl.Matchers.GroupMatcher<JobKey>.GroupEquals(JobHelp.jobGroupName)).Count - 1);
                }
                //系统作业执行完毕
                Log.Logger.InfoFormat("系统轮询作业执行完毕,目前共{0}个作业正在运行。", context.Scheduler.GetJobKeys(Quartz.Impl.Matchers.GroupMatcher<JobKey>.GroupEquals(JobHelp.jobGroupName)).Count);
                context.Put("ExecResult", "系统作业执行完成。");
    
                //Log.Logger.ErrorFormat("本次运行时间{0},下次运行时间{1}", DateTime.Now.ToString(), context.NextFireTimeUtc.Value.DateTime.AddHours(8).ToString());
            }
    复制代码

    主要的应该也就这些,当然这是个Demo,有很多地方不是很完善。

    源码下载

    https://git.oschina.net/bin88123/TaskManageDemo

  • 相关阅读:
    使用 asp.net mvc和 jQuery UI 控件包
    ServiceStack.Redis 使用教程
    HTC T8878刷机手册
    Entity Framework CodeFirst 文章汇集
    2011年Mono发展历程
    日志管理实用程序LogExpert
    使用 NuGet 管理项目库
    WCF 4.0路由服务Routing Service
    精进不休 .NET 4.0 (1) asp.net 4.0 新特性之web.config的改进, ViewStateMode, ClientIDMode, EnablePersistedSelection, 控件的其它一些改进
    精进不休 .NET 4.0 (7) ADO.NET Entity Framework 4.0 新特性
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/5551823.html
Copyright © 2011-2022 走看看