Quartz.NET
- Quartz.NET是一个功能齐全的开源作业调度系统,可用于从最小的应用程序到大型企业系统。
- Quartz.NET是一个用C#编写的纯.NET库,是对JAVA开源调度框架Quartz的移植。目前支持.Net Core
- Quartz.NET官方地址:https://www.quartz-scheduler.net/
- Quartz.NetUI维护了常用作业添加、删除、修改、停止、启动功能,直接使用cron表达式设置作业执行间隔,有完整的日志记录。
1.Quartz.NetUI 开发环境
.net core2.1及以上版本、vs2017、Quartz.NET 3.0.7 、 vue 2.0 、IView
2.开箱即用、不依赖数据库
- 直接运行Quartz.NetUI\Quartz.NET.Web目录下run.bat文件或部署项目
- 登陆口令token位于appsettings.json节点token
- 管理员帐号位于appsettings.json节点superToken
3.主要代码文件
- QuartzSettings 文件夹由系统自动生成,与项目文件夹同级,存放作业配置信息及日志信息(发布时不需要发布或复制此文件夹)
- TaskAuthorizeFilter.cs 帐号权限、AllowAnonymous过滤
- QuartzNETExtension.cs 处理作业添加、删除、修改、停止、启动功能
- FileQuartz.cs 集中处理作业相关日志
- HttpManager.cs 接口处理
- HealthController 对外开放的健康检查接口,判断作业站点是否处理活动状态。
- TaskOptions.cs 作业相关字段
- TaskBackGround/Index.cshtml 作业UI
- task-index.js 前端Vue+IView
4.在线演示地址
- http://task.volcore.xyz 登陆口令:task123456
- GitHub:https://github.com/cq-panda/Quartz.NetUI
5、作业添加、删除、修改、停止、启动功能
/// <summary> /// 添加作业 /// </summary> /// <param name="taskOptions"></param> /// <param name="schedulerFactory"></param> /// <param name="init">是否初始化,否=需要重新生成配置文件,是=不重新生成配置文件</param> /// <returns></returns> public static async Task<object> AddJob(this TaskOptions taskOptions, ISchedulerFactory schedulerFactory, bool init = false) { try { (bool, string) validExpression = taskOptions.Interval.IsValidExpression(); if (!validExpression.Item1) return new { status = false, msg = validExpression.Item2 }; (bool, object) result = taskOptions.Exists(init); if (!result.Item1) return result.Item2; if (!init) { _taskList.Add(taskOptions); FileQuartz.WriteJobConfig(_taskList); } IJobDetail job = JobBuilder.Create<HttpResultful>() .WithIdentity(taskOptions.TaskName, taskOptions.GroupName) .Build(); ITrigger trigger = TriggerBuilder.Create() .WithIdentity(taskOptions.TaskName, taskOptions.GroupName) .StartNow().WithDescription(taskOptions.Describe) .WithCronSchedule(taskOptions.Interval) .Build(); IScheduler scheduler = await schedulerFactory.GetScheduler(); await scheduler.ScheduleJob(job, trigger); if (taskOptions.Status == (int)TriggerState.Normal) { await scheduler.Start(); } else { await schedulerFactory.Pause(taskOptions); FileQuartz.WriteStartLog($"作业:{taskOptions.TaskName},分组:{taskOptions.GroupName},新建时未启动原因,状态为:{taskOptions.Status}"); } if (!init) FileQuartz.WriteJobAction(JobAction.新增, taskOptions.TaskName, taskOptions.GroupName); } catch (Exception ex) { return new { status = false, msg = ex.Message }; } return new { status = true }; } /// <summary> /// 移除作业 /// </summary> /// <param name="schedulerFactory"></param> /// <param name="taskName"></param> /// <param name="groupName"></param> /// <returns></returns> public static Task<object> Remove(this ISchedulerFactory schedulerFactory, TaskOptions taskOptions) { return schedulerFactory.TriggerAction(taskOptions.TaskName, taskOptions.GroupName, JobAction.删除, taskOptions); } /// <summary> /// 更新作业 /// </summary> /// <param name="schedulerFactory"></param> /// <param name="taskOptions"></param> /// <returns></returns> public static Task<object> Update(this ISchedulerFactory schedulerFactory, TaskOptions taskOptions) { return schedulerFactory.TriggerAction(taskOptions.TaskName, taskOptions.GroupName, JobAction.修改, taskOptions); } /// <summary> /// 暂停作业 /// </summary> /// <param name="schedulerFactory"></param> /// <param name="taskOptions"></param> /// <returns></returns> public static Task<object> Pause(this ISchedulerFactory schedulerFactory, TaskOptions taskOptions) { return schedulerFactory.TriggerAction(taskOptions.TaskName, taskOptions.GroupName, JobAction.暂停, taskOptions); } /// <summary> /// 启动作业 /// </summary> /// <param name="schedulerFactory"></param> /// <param name="taskOptions"></param> /// <returns></returns> public static Task<object> Start(this ISchedulerFactory schedulerFactory, TaskOptions taskOptions) { return schedulerFactory.TriggerAction(taskOptions.TaskName, taskOptions.GroupName, JobAction.开启, taskOptions); } /// <summary> /// 立即执行一次作业 /// </summary> /// <param name="schedulerFactory"></param> /// <param name="taskOptions"></param> /// <returns></returns> public static Task<object> Run(this ISchedulerFactory schedulerFactory, TaskOptions taskOptions) { return schedulerFactory.TriggerAction(taskOptions.TaskName, taskOptions.GroupName, JobAction.立即执行, taskOptions); } public static object ModifyTaskEntity(this TaskOptions taskOptions, ISchedulerFactory schedulerFactory, JobAction action) { TaskOptions options = null; object result = null; switch (action) { case JobAction.删除: for (int i = 0; i < _taskList.Count; i++) { options = _taskList[i]; if (options.TaskName == taskOptions.TaskName && options.GroupName == taskOptions.GroupName) { _taskList.RemoveAt(i); } } break; case JobAction.修改: options = _taskList.Where(x => x.TaskName == taskOptions.TaskName && x.GroupName == taskOptions.GroupName).FirstOrDefault(); //移除以前的配置 if (options != null) { _taskList.Remove(options); } //生成任务并添加新配置 result = taskOptions.AddJob(schedulerFactory, false).GetAwaiter().GetResult(); break; case JobAction.暂停: case JobAction.开启: case JobAction.停止: case JobAction.立即执行: options = _taskList.Where(x => x.TaskName == taskOptions.TaskName && x.GroupName == taskOptions.GroupName).FirstOrDefault(); if (action == JobAction.暂停) { options.Status = (int)TriggerState.Paused; } else if (action == JobAction.停止) { options.Status = (int)action; } else { options.Status = (int)TriggerState.Normal; } break; } //生成配置文件 FileQuartz.WriteJobConfig(_taskList); FileQuartz.WriteJobAction(action, taskOptions.TaskName, taskOptions.GroupName, "操作对象:"+JsonConvert.SerializeObject(taskOptions)); return result; } /// <summary> /// 触发新增、删除、修改、暂停、启用、立即执行事件 /// </summary> /// <param name="schedulerFactory"></param> /// <param name="taskName"></param> /// <param name="groupName"></param> /// <param name="action"></param> /// <param name="taskOptions"></param> /// <returns></returns> public static async Task<object> TriggerAction(this ISchedulerFactory schedulerFactory, string taskName, string groupName, JobAction action, TaskOptions taskOptions = null) { string errorMsg = ""; try { IScheduler scheduler = await schedulerFactory.GetScheduler(); List<JobKey> jobKeys = scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(groupName)).Result.ToList(); if (jobKeys == null || jobKeys.Count() == 0) { errorMsg = $"未找到分组[{groupName}]"; return new { status = false, msg = errorMsg }; } JobKey jobKey = jobKeys.Where(s => scheduler.GetTriggersOfJob(s).Result.Any(x => (x as CronTriggerImpl).Name == taskName)).FirstOrDefault(); if (jobKey == null) { errorMsg = $"未找到触发器[{taskName}]"; return new { status = false, msg = errorMsg }; } var triggers = await scheduler.GetTriggersOfJob(jobKey); ITrigger trigger = triggers?.Where(x => (x as CronTriggerImpl).Name == taskName).FirstOrDefault(); if (trigger == null) { errorMsg = $"未找到触发器[{taskName}]"; return new { status = false, msg = errorMsg }; } object result = null; switch (action) { case JobAction.删除: case JobAction.修改: await scheduler.PauseTrigger(trigger.Key); await scheduler.UnscheduleJob(trigger.Key);// 移除触发器 await scheduler.DeleteJob(trigger.JobKey); result = taskOptions.ModifyTaskEntity(schedulerFactory, action); break; case JobAction.暂停: case JobAction.停止: case JobAction.开启: result = taskOptions.ModifyTaskEntity(schedulerFactory, action); if (action == JobAction.暂停) { await scheduler.PauseTrigger(trigger.Key); } else if (action == JobAction.开启) { await scheduler.ResumeTrigger(trigger.Key); // await scheduler.RescheduleJob(trigger.Key, trigger); } else { await scheduler.Shutdown(); } break; case JobAction.立即执行: await scheduler.TriggerJob(jobKey); break; } return result ?? new { status = true, msg = $"作业{action.ToString()}成功" }; } catch (Exception ex) { errorMsg = ex.Message; return new { status = false, msg = ex.Message }; } finally { FileQuartz.WriteJobAction(action, taskName, groupName, errorMsg); } }
作业UI部份截图
作业列表
新建作业
修改作业
查看日志
配置文件QuartzSettings
配置文件QuartzSettings由系统自动生成,所在位置与当前项目同级,生成文件包括作业参数配置及日志文件初始化
配置文件目录结构
├─Constant
│ QuartzFileInfo.cs
│
├─Controllers
│ HealthController.cs
│ HomeController.cs
│ TaskBackGroundController.cs
│
├─Enum
│ JobAction.cs
│
├─Extensions
│ ConvertPath.cs
│ QuartzNETExtension.cs
│
├─Filters
│ TaskAuthorizeFilter.cs
│
├─Models
│ TaskLog.cs
│ TaskOptions.cs
│
├─Utility
│ FileHelper.cs
│ FileQuartz.cs
│ HttpManager.cs
│ HttpResultful.cs
│ TaskCurrent.cs
│
├─Views
│─TaskBackGround
│ Index.cshtml
│
└─wwwroot
│ task_index.css
│
├─iView
│ iview.min.js
│
├─js
│ task-index.js
└─vue
vue.js