您的位置:首页 > 其它

一个任务调度

2016-05-31 15:08 267 查看
最近把以前项目中用的任务调度提了出来,做了一个Demo。

/// <summary>
/// 使用作业计划来创建作业
/// </summary>
/// <param name="quartzScheduler">调度器</param>
/// <param name="task">作业任务</param>
/// <returns>二元组</returns>
public static Tuple<IJobDetail, ITrigger> CreatScheduleJob(IScheduler quartzScheduler, ScheduleTask task)
{
Tuple<IJobDetail, ITrigger> tuple = null;
IJobDetail ij = CreateJobDetail(task);
ITrigger it = CreateTrigger(task);

quartzScheduler.ScheduleJob(ij, it);
tuple = new Tuple<IJobDetail, ITrigger>(ij, it);

return tuple;
}


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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: