-clouds

 Quartz.NET

  • Quartz.Net 定制UI维护了常用作业添加、删除、修改、停止、启动功能,直接使用cron表达式设置作业执行间隔,有完整的日志记录。
  • Quartz.NET是一个功能齐全的开源作业调度系统,可用于从最小的应用程序到大型企业系统。
  • Quartz.NET是一个用C#编写的纯.NET库,是对JAVA开源调度框架Quartz的移植。目前支持.Net Core
  • Quartz.NET官方地址:https://www.quartz-scheduler.net/

 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、身份、控制器过滤 TaskAuthorizeFilter.cs

   private readonly IHttpContextAccessor _accessor;
        private readonly IMemoryCache _memoryCache;
        public TaskAuthorizeFilter(IHttpContextAccessor accessor, IMemoryCache memoryCache)
        {
            this._accessor = accessor;
            this._memoryCache = memoryCache;
        }

        public void OnAuthorization(AuthorizationFilterContext context)
        {
            WriteLog();
            if (context.Filters.Any(item => item is IAllowAnonymousFilter))
                return;
            if (((ControllerActionDescriptor)context.ActionDescriptor).MethodInfo
                .CustomAttributes.Any(x => x.AttributeType == typeof(TaskAuthorAttribute))
                && !_memoryCache.Get<bool>("isSuperToken"))
            {
                context.Result = new ContentResult()
                {
                    Content = JsonConvert.SerializeObject(new
                    {
                        status =false,
                        msg = "普通帐号不能进行此操作!可通过appsettings.json节点superToken获取管理员帐号。"
                    }),
                    ContentType = "application/json",
                    StatusCode = (int)HttpStatusCode.OK
                };
            }
        }

  

5、作业触发器操作 QuartzNETExtension.cs

        /// <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);
            }
        }

  

6、作业日志记录 FileQuartz.cs

    public class FileQuartz
    {
        private static string _rootPath { get; set; }

        private static string _logPath { get; set; }
        /// <summary>
        /// 创建作业所在根目录及日志文件夹 
        /// </summary>
        /// <returns></returns>
        public static string CreateQuartzRootPath(IHostingEnvironment env)
        {
            if (!string.IsNullOrEmpty(_rootPath))
                return _rootPath;
            _rootPath = $"{Directory.GetParent(env.ContentRootPath).FullName}\\{QuartzFileInfo.QuartzSettingsFolder}\\";
            _rootPath = _rootPath.ReplacePath();
            if (!Directory.Exists(_rootPath))
            {
                Directory.CreateDirectory(_rootPath);
            }
            _logPath = _rootPath + QuartzFileInfo.Logs + "\\";
            _logPath = _logPath.ReplacePath();
            //生成日志文件夹
            if (!Directory.Exists(_logPath))
            {
                Directory.CreateDirectory(_logPath);
            }
            return _rootPath;
        }

        /// <summary>
        /// 初始化作业日志文件,以txt作为文件
        /// </summary>
        /// <param name="groupJobName"></param>
        public static void InitGroupJobFileLog(string groupJobName)
        {
            string jobFile = _logPath + groupJobName;
            jobFile = jobFile.ReplacePath();
            if (!File.Exists(jobFile))
            {
                File.Create(jobFile);
            }
        }

        public static List<TaskLog> GetJobRunLog(string taskName, string groupName, int page, int pageSize = 100)
        {
            string path = $"{_logPath}{groupName}\\{taskName}.txt";
            List<TaskLog> list = new List<TaskLog>();

            path = path.ReplacePath();
            if (!File.Exists(path))
                return list;
            var logs = FileHelper.ReadPageLine(path, page, pageSize, true);
            foreach (string item in logs)
            {
                string[] arr = item?.Split('_');
                if (item == "" || arr == null || arr.Length == 0)
                    continue;
                if (arr.Length != 3)
                {
                    list.Add(new TaskLog() { Msg = item });
                    continue;
                }
                list.Add(new TaskLog() { BeginDate = arr[0], EndDate = arr[1], Msg = arr[2] });
            }
            return list.OrderByDescending(x => x.BeginDate).ToList();
        }

        public static void WriteJobConfig(List<TaskOptions> taskList)
        {
            string jobs = JsonConvert.SerializeObject(taskList);
            //写入配置文件
            FileHelper.WriteFile(_rootPath, QuartzFileInfo.JobConfigFileName, jobs);
        }

        public static void WriteStartLog(string content)
        {
            content = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "," + content;
            if (!content.EndsWith("\r\n"))
            {
                content += "\r\n";
            }
            FileHelper.WriteFile(FileQuartz.LogPath, "start.txt", content, true);
        }
        public static void WriteJobAction(JobAction jobAction, ITrigger trigger, string taskName, string groupName)
        {
            WriteJobAction(jobAction, taskName, groupName, trigger == null ? "未找到作业" : "OK");
        }
        public static void WriteJobAction(JobAction jobAction, string taskName, string groupName, string content = null)
        {
            content = $"{jobAction.ToString()} --  {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}  --分组:{groupName},作业:{taskName},消息:{content ?? "OK"}\r\n";
            FileHelper.WriteFile(FileQuartz.LogPath, "action.txt", content, true);
        }

        public static void WriteAccess(string content = null)
        {
            content = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}_{content}\r\n";
            FileHelper.WriteFile(FileQuartz.LogPath, "access.txt", content, true);
        }

        public static string GetAccessLog(int pageSize=1)
        {
            string path = FileQuartz.LogPath + "access.txt";
            path = path.ReplacePath();
            if (!File.Exists(path))
                return "没有找到目录";
            return string.Join("<br/>", FileHelper.ReadPageLine(path, pageSize, 5000, true).ToList());
        }
        public static string RootPath
        {
            get { return _rootPath; }
        }

        public static string LogPath
        {
            get { return _logPath; }
        }
    }

  

UI

7.在线演示地址

  • http://task.volcore.xyz 登陆口令:task123456
  • GitHub:https://github.com/cq-panda/Quartz.NetUI

 

分类:

技术点:

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-06-19
  • 2022-12-23
  • 2021-11-29
猜你喜欢
  • 2019-05-29
  • 2022-12-23
  • 2021-10-12
  • 2021-12-19
  • 2021-11-29
  • 2021-11-01
  • 2021-07-14
相关资源
相似解决方案