今天抽出一点点时间来造一个小轮子,是关于定时任务这块的。
这篇文章主要从一下几点介绍:
- 创建数据库管理表
- 创建web项目
- 引入quarzt nuget 包
- 写具体配置操作,实现定时任务处理
第一步:创建一个空web项目,引入quarzt nuget 包
创建TB.AspNetCore.Quartz web项目和TB.AspNetCore.Data 类库,在web项目中引入Quartz nuget包
第二部:数据库创建一张管理表
-- ---------------------------- -- Table structure for ScheduleInfo -- ---------------------------- DROP TABLE IF EXISTS `ScheduleInfo`; CREATE TABLE `ScheduleInfo` ( `Id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号', `JobGroup` varchar(100) NOT NULL DEFAULT '' COMMENT '任务组', `JobName` varchar(50) NOT NULL DEFAULT '' COMMENT '任务名', `RunStatus` int(11) NOT NULL DEFAULT '0' COMMENT '运行状态', `CromExpress` varchar(40) NOT NULL DEFAULT '' COMMENT 'Crom表达式', `StarRunTime` datetime DEFAULT NULL COMMENT '开始运行时间', `EndRunTime` datetime DEFAULT NULL COMMENT '结束运行时间', `NextRunTime` datetime DEFAULT NULL COMMENT '下次运行时间', `Token` varchar(40) NOT NULL DEFAULT '' COMMENT 'Token', `AppID` varchar(40) NOT NULL DEFAULT '' COMMENT 'AppID', `ServiceCode` varchar(40) DEFAULT NULL, `InterfaceCode` varchar(40) DEFAULT NULL, `TaskDescription` varchar(200) DEFAULT NULL, `DataStatus` int(11) DEFAULT NULL COMMENT '数据状态', `CreateAuthr` varchar(30) DEFAULT NULL COMMENT '创建人', `CreateTime` datetime DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`Id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
创建数据库的表结构如图所示,接下来我们在Data项目里添加mysql数据库驱动nuget包
打开PM,执行数据库反向工程命令,从数据库生成model实体
Scaffold-DbContext "Server=你的服务器地址;Database=你的数据库;User=数据库用户名;Password=你的数据库密码;" "Pomelo.EntityFrameworkCore.MySql" -OutputDir Entity**2.1.1 建议不要选用,防坑!
将链接字符串换成你自己的,我们又新添加了一个service文件夹和一个Enum文件夹
其中,BaseService 里封装了针对数据操作的基本crud,quartz里封装了关于定时任务的配置,enum里枚举了任务状态,具体代码如下
public enum JobStatus { [Description("已启用")] 已启用, [Description("运行中")] 待运行, [Description("执行中")] 执行中, [Description("执行完成")] 执行完成, [Description("执行任务计划中")] 执行任务计划中, [Description("已停止")] 已停止, }
下面是baseservice里具体方法
public class BaseService { protected static object obj = new object(); public ggb_offlinebetaContext _context; protected ggb_offlinebetaContext DataContext { get { if (_context == null) { _context = new ggb_offlinebetaContext(); } return _context; } } public BaseService() { } #region 封装基crud /// <summary> /// 只能是唯一记录 多记录引发异常 /// </summary> /// <typeparam name="TSource"></typeparam> /// <param name="predicate"></param> /// <returns></returns> public TSource Single<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class { if (predicate == null) { return this.DataContext.Set<TSource>().SingleOrDefault(); } return this.DataContext.Set<TSource>().SingleOrDefault(predicate); } /// <summary> /// 查询一条记录 /// </summary> /// <typeparam name="TSource"></typeparam> /// <param name="predicate"></param> /// <returns></returns> public TSource First<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class { if (predicate == null) { return this.DataContext.Set<TSource>().FirstOrDefault(); } return this.DataContext.Set<TSource>().FirstOrDefault(predicate); } /// <summary> /// where条件查询 /// </summary> /// <typeparam name="TSource"></typeparam> /// <param name="predicate"></param> /// <returns></returns> public IQueryable<TSource> Where<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class { if (predicate == null) { return this.DataContext.Set<TSource>().AsQueryable(); } return this.DataContext.Set<TSource>().Where(predicate); } /// <summary> /// 记录数 /// </summary> /// <typeparam name="TSource"></typeparam> /// <param name="predicate"></param> /// <returns></returns> public int Count<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class { if (predicate == null) { return this.DataContext.Set<TSource>().Count(); } return this.DataContext.Set<TSource>().Count(predicate); } /// <summary> /// 根据条件判断记录是否存在 /// </summary> /// <typeparam name="TSource"></typeparam> /// <param name="predicate"></param> /// <returns></returns> /// Any确定序列是否包含任何元素 public bool Exists<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class { if (predicate == null) { return this.DataContext.Set<TSource>().Any(); } return this.DataContext.Set<TSource>().Any(predicate); } /// <summary> /// 查询全部 /// </summary> /// <typeparam name="TSource"></typeparam> /// <returns></returns> public IQueryable<TSource> Query<TSource>() where TSource : class { return this.DataContext.Set<TSource>(); } /// <summary> /// paging the query 分页查询 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="query"></param> /// <param name="pageIndex">page index</param> /// <param name="pageSize">page size </param> /// <param name="count">total row record count</param> /// <returns></returns> public IQueryable<T> Pages<T>(IQueryable<T> query, int pageIndex, int pageSize, out int count) where T : class { if (pageIndex < 1) { pageIndex = 1; } if (pageSize < 1) { pageSize = 10; } count = query.Count(); query = query.Skip((pageIndex - 1) * pageSize).Take(pageSize); return query; } /// <summary> /// 分页查询 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="pageIndex"></param> /// <param name="pageSize"></param> /// <param name="count"></param> /// <returns></returns> public IQueryable<T> Pages<T>(int pageIndex, int pageSize, out int count) where T : class { if (pageIndex < 1) { pageIndex = 1; } if (pageSize < 1) { pageSize = 10; } var query = this.DataContext.Set<T>().AsQueryable(); count = query.Count(); query = query.Skip((pageIndex - 1) * pageSize).Take(pageSize); return query; } #endregion /// <summary> /// 做一次提交 /// </summary> #region Save Changes public void Save() { //todo 需要验证是否需要释放 using (this.DataContext) { this.DataContext.SaveChanges(); } } /// <summary> /// 添加 /// </summary> /// <param name="entity"></param> /// <param name="save"></param> public void Add(object entity, bool save = false) { this.DataContext.Add(entity); if (save) { this.Save(); } } /// <summary> /// 更新实体 /// </summary> /// <param name="entity"></param> /// <param name="save"></param> public void Update(object entity, bool save = false) { this.DataContext.Update(entity); if (save) { this.Save(); } } /// <summary> /// 更新2 /// </summary> /// <param name="list"></param> /// <param name="save"></param> public void Update(IEnumerable<object> list, bool save = false) { this.DataContext.UpdateRange(list); if (save) { this.Save(); } } /// <summary> /// 删除1 /// </summary> /// <param name="entity"></param> /// <param name="save"></param> public void Delete(object entity, bool save = false) { this.DataContext.Remove(entity); if (save) { this.Save(); } } /// <summary> /// 删除2 /// </summary> /// <param name="list"></param> /// <param name="save"></param> public void Delete(IEnumerable<object> list, bool save = false) { this.DataContext.RemoveRange(list); if (save) { this.Save(); } } #endregion ///// <summary> ///// 释放资源 ///// </summary> //public void Dispose() //{ // _context.Dispose(); //} }
下面是任务调度中心代码
/// <summary> /// 任务调度中心 /// </summary> public class JobCenter { /// <summary> /// 任务计划 /// </summary> public static IScheduler scheduler = null; public static async Task<IScheduler> GetSchedulerAsync() { if (scheduler != null) { return scheduler; } else { ISchedulerFactory schedf = new StdSchedulerFactory(); IScheduler sched = await schedf.GetScheduler(); return sched; } } /// <summary> /// 添加任务计划//或者进程终止后的开启 /// </summary> /// <returns></returns> public async Task<bool> AddScheduleJobAsync(ScheduleInfo m) { try { if (m != null) { if (m.StarRunTime == null) { m.StarRunTime = DateTime.Now; } DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(m.StarRunTime, 1); if (m.EndRunTime == null) { m.EndRunTime = DateTime.MaxValue.AddDays(-1); } DateTimeOffset endRunTime = DateBuilder.NextGivenSecondDate(m.EndRunTime, 1); scheduler = await GetSchedulerAsync(); IJobDetail job = JobBuilder.Create<HttpJob>() .WithIdentity(m.JobName, m.JobGroup) .Build(); ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create() .StartAt(starRunTime) .EndAt(endRunTime) .WithIdentity(m.JobName, m.JobGroup) .WithCronSchedule(m.CromExpress) .Build(); //将信息写入 new ScheduleManage().AddSchedule(m); await scheduler.ScheduleJob(job, trigger); await scheduler.Start(); await StopScheduleJobAsync(m.JobGroup, m.JobName); return true; } return false; } catch (Exception ex) { //MyLogger.WriteError(ex, null); return false; } } /// <summary> /// 暂停指定任务计划 /// </summary> /// <returns></returns> public async Task<string> StopScheduleJobAsync(string jobGroup, string jobName) { try { scheduler = await GetSchedulerAsync(); //使任务暂停 await scheduler.PauseJob(new JobKey(jobName, jobGroup)); //更新数据库 new ScheduleManage().UpdateScheduleStatus(new ScheduleInfo() { JobName = jobName, JobGroup = jobGroup, RunStatus = (int)JobStatus.已停止 }); var status = new StatusViewModel() { Status = 0, Msg = "暂停任务计划成功", }; return JsonConvert.SerializeObject(status); } catch (Exception ex) { //MyLogger.WriteError(ex, null); var status = new StatusViewModel() { Status = -1, Msg = "暂停任务计划失败", }; return JsonConvert.SerializeObject(status); } } /// <summary> /// 恢复指定的任务计划**恢复的是暂停后的任务计划,如果是程序奔溃后 或者是进程杀死后的恢复,此方法无效 /// </summary> /// <returns></returns> public async Task<string> RunScheduleJobAsync(string jobGroup, string jobName) { try { //获取model var sm = new ScheduleManage().GetScheduleModel(new ScheduleInfo() { JobName = jobName, JobGroup = jobGroup }); await AddScheduleJobAsync(sm); sm.RunStatus = (int)JobStatus.已启用; //更新model new ScheduleManage().UpdateScheduleStatus(sm); scheduler = await GetSchedulerAsync(); //resumejob 恢复 await scheduler.ResumeJob(new JobKey(jobName, jobGroup)); var status = new StatusViewModel() { Status = 0, Msg = "开启任务计划成功", }; return JsonConvert.SerializeObject(status); } catch (Exception ex) { var status = new StatusViewModel() { Status = -1, Msg = "开启任务计划失败", }; return JsonConvert.SerializeObject(status); } } }
其他几个文件的细节代码我就不再粘贴,详细代码会推到github上去,接下来写一个控制器看看效果!
第四部:项目运行截图
具体详细的东西,也没有说的十分清晰,具体的代码可以到github上去查看,
项目github地址:https://github.com/TopGuo/TB.AspNetCore.Quarzt
如果您认为这篇文章还不错或者有所收获,您可以点击右下角的【推荐】按钮精神支持,因为这种支持是我继续写作,分享的最大动力
欢迎大家关注我都我的微信 公众号,公众号涨粉丝人数,就是你们对我的喜爱程度!