基于Quartz.net的远程任务管理系统 一
在上一篇绪中,已经介绍了整个项目的情况下了,接下来就是开始一步步做起来了。
首先:先整个我们的Job任务表,以及Job执行日志表。SQL如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 drop table if exists job_info; 2 create table job_info 3 ( 4 id int not null AUTO_INCREMENT comment '主键', 5 job_name varchar(150) null default null comment '任务名称', 6 job_assembly varchar(200) null default null comment '执行的方式的dll名称', 7 job_class varchar(300) null default null comment '执行的方法类', 8 job_corn varchar(100) null default null comment '执行任务的corn表达式', 9 job_type int not null default 1 comment '任务类型,默认为1 简单,2 复杂', 10 job_execount int null default 0 comment '任务的执行总次数,0表示无限次', 11 job_starttime datetime null default null comment '任务开始时间', 12 job_state int null default 0 comment '任务的状态 0 准备中,1 执行中,2 暂定,3 停止,4 结束', 13 addtime TIMESTAMP null default CURRENT_TIMESTAMP comment '任务的创建时间', 14 PRIMARY KEY (`id`) 15 ); 16 drop table if exists job_log; 17 create table job_log 18 ( 19 id int not null AUTO_INCREMENT comment '主键', 20 job_name varchar(150) null default null comment '任务名称', 21 job_result varchar(200) null default null comment '执行的结果', 22 job_exception text null default null comment '执行任务的异常信息', 23 job_exetime int not null default 0 comment '执行耗时,单位ms', 24 job_exedate datetime null default 0 comment '任务的执行的日期时间', 25 job_exestate int null default 0 comment '执行结果 0 正常,1 异常', 26 addtime TIMESTAMP null default CURRENT_TIMESTAMP comment '任务的执行时间', 27 PRIMARY KEY (`id`) 28 );
相关实体类与操作方法,如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /// <summary> 2 /// Job信息表 3 /// </summary> 4 public class Job_Info : BaseEntity 5 { 6 private int _id = 0; 7 private string _job_name; 8 private string _job_assembly; 9 private string _job_class; 10 private string _job_corn; 11 private int _job_type = 1; 12 private int _job_execount = 0; 13 private DateTime _job_starttime; 14 private int _job_state = 0; 15 private DateTime _addtime; 16 17 /// <summary> 18 /// 主键 19 /// </summary> 20 public int Id { get => _id; set => _id = value; } 21 /// <summary> 22 /// 任务名称 23 /// </summary> 24 public string Job_name { get => _job_name; set => _job_name = value; } 25 /// <summary> 26 /// 执行的方式的dll名称 27 /// </summary> 28 public string Job_assembly { get => _job_assembly; set => _job_assembly = value; } 29 /// <summary> 30 /// 执行的方法类 31 /// </summary> 32 public string Job_class { get => _job_class; set => _job_class = value; } 33 /// <summary> 34 /// 执行任务的corn表达式 35 /// </summary> 36 public string Job_corn { get => _job_corn; set => _job_corn = value; } 37 /// <summary> 38 /// 任务类型,默认为1 简单,2 复杂 39 /// </summary> 40 public int Job_type { get => _job_type; set => _job_type = value; } 41 /// <summary> 42 /// 任务的执行总次数,0表示无限次 43 /// </summary> 44 public int Job_execount { get => _job_execount; set => _job_execount = value; } 45 /// <summary> 46 /// 任务开始时间 47 /// </summary> 48 public DateTime Job_starttime { get => _job_starttime; set => _job_starttime = value; } 49 /// <summary> 50 /// 任务的状态 0 准备中,1 执行中,2 暂定,3 停止,4 结束 51 /// </summary> 52 public int Job_state { get => _job_state; set => _job_state = value; } 53 /// <summary> 54 /// 任务的创建时间 55 /// </summary> 56 public DateTime Addtime { get => _addtime; set => _addtime = value; } 57 58 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// Job运行日志表 /// </summary> public class Job_Log : BaseEntity { private int _id = 0; private string _job_name; private string _job_result; private string _job_exception; private int _job_exetime; private DateTime _job_exedate; private int _job_exestate; private DateTime _addtime; /// <summary> /// 主键 /// </summary> public int Id { get => _id; set => _id = value; } /// <summary> /// 任务名称 /// </summary> public string Job_name { get => _job_name; set => _job_name = value; } /// <summary> /// 执行的结果 /// </summary> public string Job_result { get => _job_result; set => _job_result = value; } /// <summary> /// 执行任务的异常信息 /// </summary> public string Job_exception { get => _job_exception; set => _job_exception = value; } /// <summary> /// 执行耗时,单位ms /// </summary> public int Job_exetime { get => _job_exetime; set => _job_exetime = value; } /// <summary> /// 任务的执行的日期时间 /// </summary> public DateTime Job_exedate { get => _job_exedate; set => _job_exedate = value; } /// <summary> /// 执行结果 0 正常,1 异常 /// </summary> public int Job_exestate { get => _job_exestate; set => _job_exestate = value; } /// <summary> /// 任务的执行时间 /// </summary> public DateTime Addtime { get => _addtime; set => _addtime = value; } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /// <summary> 2 /// Job信息逻辑类 3 /// </summary> 4 public class JobInfoBLL 5 { 6 /// <summary> 7 /// 添加Job信息 8 /// </summary> 9 /// <param name="jobInfo"></param> 10 /// <returns></returns> 11 public int AddInfo(Job_Info jobInfo) 12 { 13 int result = 0; 14 15 if (jobInfo == null) 16 return result; 17 try 18 { 19 string SqlStr = string.Format("insert into job_info(job_name,job_assembly,job_class,job_corn,job_type,job_execount,job_starttime,job_state) values('{0}','{1}','{7}','{2}',{3},{4},'{5}',{6})", 20 jobInfo.Job_name, jobInfo.Job_assembly, jobInfo.Job_corn, jobInfo.Job_type, jobInfo.Job_execount, jobInfo.Job_starttime.ToString("yyyy-MM-dd HH:mm:ss"), 0, jobInfo.Job_class); 21 result = MySqlHelper.ExceuteSql(SqlStr); 22 } 23 finally 24 { 25 26 } 27 28 return result; 29 } 30 31 /// <summary> 32 /// 更新Job的状态 33 /// </summary> 34 /// <param name="jobInfo"></param> 35 /// <returns></returns> 36 public int UpdateJobState(Job_Info jobInfo) 37 { 38 int result = 0; 39 40 if (jobInfo == null) 41 return result; 42 try 43 { 44 string SqlStr = string.Format("update job_info set job_state={0} where ", jobInfo.Job_state); 45 if(jobInfo.Id > 0) 46 { 47 SqlStr += string.Format(" id={0};", jobInfo.Id); 48 }else if (!string.IsNullOrEmpty(jobInfo.Job_name)) 49 { 50 SqlStr += string.Format(" job_name='{0}'", jobInfo.Job_name); 51 } 52 result = MySqlHelper.ExceuteSql(SqlStr); 53 } 54 finally 55 { 56 57 } 58 59 return result; 60 } 61 62 /// <summary> 63 /// job列表 64 /// </summary> 65 /// <returns></returns> 66 public List<Job_Info> GetJobList() 67 { 68 List<Job_Info> list = null; 69 70 try 71 { 72 string SqlStr = "select * from job_info"; 73 var ds = MySqlHelper.GetDataSet(SqlStr); 74 if(ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0) 75 { 76 list = new List<Job_Info>(); 77 Job_Info info = new Job_Info(); 78 foreach (System.Data.DataRow row in ds.Tables[0].Rows) 79 { 80 info = Job_Info.ToEntity<Job_Info>(row, info); 81 if (info != null) 82 list.Add(info); 83 } 84 } 85 } 86 finally 87 { 88 89 } 90 91 return list; 92 } 93 94 /// <summary> 95 /// job列表 96 /// </summary> 97 /// <returns></returns> 98 public List<Job_Info> GetJobList(int pageIndex,int pageSize) 99 { 100 List<Job_Info> list = null; 101 102 try 103 { 104 string SqlStr = "select * from job_info"; 105 SqlStr += string.Format(" limit {0},{1};", (pageIndex - 1) * pageSize, pageSize); 106 var ds = MySqlHelper.GetDataSet(SqlStr); 107 if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0) 108 { 109 list = new List<Job_Info>(); 110 Job_Info info = new Job_Info(); 111 foreach (System.Data.DataRow row in ds.Tables[0].Rows) 112 { 113 info = Job_Info.ToEntity<Job_Info>(row, info); 114 if (info != null) 115 list.Add(info); 116 } 117 } 118 } 119 finally 120 { 121 122 } 123 124 return list; 125 } 126 127 public Job_Info GetOne(int id) 128 { 129 Job_Info job = null; 130 131 try 132 { 133 string SqlStr = "select * from job_info where id="+id; 134 var ds = MySqlHelper.GetDataSet(SqlStr); 135 if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0) 136 { 137 job = new Job_Info(); 138 foreach (System.Data.DataRow row in ds.Tables[0].Rows) 139 { 140 job = Job_Info.ToEntity<Job_Info>(row, job); 141 } 142 } 143 } 144 catch (Exception ex) 145 { 146 147 } 148 149 return job; 150 } 151 152 /// <summary> 153 /// job数量 154 /// </summary> 155 /// <returns></returns> 156 public int GetJobCount() 157 { 158 int list = 0; 159 160 try 161 { 162 string SqlStr = "select count(0) from job_log"; 163 var ds = MySqlHelper.GetReader(SqlStr); 164 if (ds != null) 165 { 166 int.TryParse(ds.ToString(), out list); 167 } 168 } 169 finally 170 { 171 172 } 173 174 return list; 175 } 176 177 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// Job 日志逻辑类 /// </summary> public class JobLogBLL { /// <summary> /// 添加Job日志信息 /// </summary> /// <param name="jobLog"></param> /// <returns></returns> public int AddLog(Job_Log jobLog) { int result = 0; if (jobLog == null) return result; try { string SqlStr = string.Format("insert into job_log(job_name,job_result,job_exception,job_exetime,job_exedate,job_exestate) values('{0}','{1}','{2}',{3},'{4}',{5})", jobLog.Job_name, jobLog.Job_result, jobLog.Job_exception, jobLog.Job_exetime, jobLog.Job_exedate.ToString("yyyy-MM-dd HH:mm:ss"), jobLog.Job_exestate); result = MySqlHelper.ExceuteSql(SqlStr); } finally { } return result; } /// <summary> /// job日志列表 /// </summary> /// <returns></returns> public List<Job_Log> GetJobLogList() { List<Job_Log> list = null; try { string SqlStr = "select * from job_log"; var ds = MySqlHelper.GetDataSet(SqlStr); if (ds != null && ds.Tables[0].Rows.Count > 0) { list = new List<Job_Log>(); Job_Log info = new Job_Log(); foreach (System.Data.DataRow row in ds.Tables[0].Rows) { info = Job_Log.ToEntity<Job_Log>(row, info); if (info != null) list.Add(info); } } } finally { } return list; } /// <summary> /// job日志列表 /// </summary> /// <returns></returns> public List<Job_Log> GetJobLogList(int pageIndex, int pageSize) { List<Job_Log> list = null; try { string SqlStr = "select * from job_log"; SqlStr += string.Format(" limit {0},{1};", (pageIndex - 1) * pageSize, pageSize); var ds = MySqlHelper.GetDataSet(SqlStr); if (ds != null && ds.Tables[0].Rows.Count > 0) { list = new List<Job_Log>(); Job_Log info = new Job_Log(); foreach (System.Data.DataRow row in ds.Tables[0].Rows) { info = Job_Log.ToEntity<Job_Log>(row, info); if (info != null) list.Add(info); } } } finally { } return list; } public int GetJobLogCount(int state = -1) { int count = 0; try { string SqlStr = "select count(0) from job_log"; if (state > -1) { SqlStr += " where job_exestate=" + state; } var ds = MySqlHelper.GetReader(SqlStr); if (ds != null) { int.TryParse(ds.ToString(), out count); } } finally { } return count; } }
这些都是数据库的基本操作,我就直接贴出来了。为了规范,我们就定了一个接口,供所有Job任务来实际业务,接口很简单,具体如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// 基Job /// </summary> public interface IJob { /// <summary> /// 执行任务 /// </summary> bool Exceute(); }
好了,下面我们就开始我们的Job托管器-Window Server。为了方便,我就使用Topshelf,因为创建JobManage.Service这个项目时,一定要选择Console项目(我一开始就直接使用了Service项目,然后一直运行不起来)。
那现在来创建一个JobServer类,实现ServiceControl, ServiceSuspend 两大接口的方法,在服务启动的时候,实例化Schedule,然后加入检查Job的Job任务,定期增加或删除Schedule里的Job。
实现如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public bool Start(HostControl hostControl) { if (JobConfig.factory == null) { JobConfig.factory = new StdSchedulerFactory(); JobConfig.scheduler = JobConfig.factory.GetScheduler(); JobConfig.scheduler.Start(); //创建循环Job IJobDetail job = JobBuilder.Create<LoopJob>().WithIdentity("LoopJob", "group1").Build(); ITrigger trigger = TriggerBuilder.Create() .WithIdentity("LoopJobtrigger", "group1") .WithCronSchedule("0 0/5 * * * ?") //30分种执行一次 .StartAt(new DateTimeOffset(DateTime.Now.AddSeconds(5))) .Build(); JobConfig.scheduler.ScheduleJob(job, trigger); } else { JobConfig.scheduler.Start(); } return true; } public bool Stop(HostControl hostControl) { if (JobConfig.factory != null) { JobConfig.scheduler.Shutdown(false); JobConfig.factory = null; JobConfig.scheduler = null; } return true; }
好了,这一节就先到这,下面的我喝杯茶再来~
源码github:https://github.com/zshankang/JobManage
如果有其他的问题,可以加QQ群:1600800