首先新建一个QuartzFileInfo类指定Quartz的保存名称及日志
/// <summary> /// Quartz配置文件名称 /// </summary> public class QuartzFileInfo { /// <summary> /// 所有任务相关存放的文件夹默认生成在当前项目类库同级(子文件夹包括:日志,作业配置) /// </summary> public static string QuartzSettingsFolder = "QuartzSettings"; //所有作业配置存储文件 public static string JobConfigFileName = "job_options.json"; /// <summary> /// 日志文件夹名称 /// </summary> public static string Logs = "QuartzLogs"; }
然后创建一个日志文件及任务持久化写入类FileHelper
public class FileHelper { private static ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim(); /// <summary> /// 通过迭代器读取txt日志内容 /// </summary> /// <param name="fullPath"></param> /// <param name="page"></param> /// <param name="pageSize"></param> /// <param name="seekEnd"></param> /// <returns></returns> public static IEnumerable<string> ReadPageLine(string fullPath, int page, int pageSize, bool seekEnd = false) { if (page <= 0) { page = 1; } fullPath = fullPath.ReplacePath(); var lines = File.ReadLines(fullPath, Encoding.UTF8); if (seekEnd) { int lineCount = lines.Count(); int linPageCount = (int)Math.Ceiling(lineCount / (pageSize * 1.00)); //超过总页数,不处理 if (page > linPageCount) { page = 0; pageSize = 0; } else if (page == linPageCount)//最后一页,取最后一页剩下所有的行 { pageSize = lineCount - (page - 1) * pageSize; if (page == 1) { page = 0; } else { page = lines.Count() - page * pageSize; } } else { page = lines.Count() - page * pageSize; } } else { page = (page - 1) * pageSize; } lines = lines.Skip(page).Take(pageSize); var enumerator = lines.GetEnumerator(); int count = 1; while (enumerator.MoveNext() || count <= pageSize) { yield return enumerator.Current; count++; } enumerator.Dispose(); } public static string ReadFile(string path) { cacheLock.EnterReadLock(); try { string text = string.Empty; path = path.ReplacePath(); if (!File.Exists(path)) return ""; using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read)) { StreamReader stream = new StreamReader(fileStream); text = stream.ReadToEnd();// 读取文件 stream.Close();//关闭流 return text; } } finally { cacheLock.ExitReadLock(); } } /// <summary> /// 写文件 /// </summary> /// <param name="Path">文件路径</param> /// <param name="Strings">文件内容</param> public static void WriteFile(string path, string fileName, string content, bool appendToLast = false) { if (!path.EndsWith("\\")) { path = path + "\\"; } path = path.ReplacePath(); if (!Directory.Exists(path))//如果不存在就创建file文件夹 { Directory.CreateDirectory(path); } using (FileStream stream = File.Open(Path.Combine(path, fileName), FileMode.OpenOrCreate, FileAccess.Write)) { byte[] by = Encoding.Default.GetBytes(content); if (appendToLast) { stream.Position = stream.Length; } else { stream.SetLength(0); } stream.Write(by, 0, by.Length); } } }
接着创建一个FileQuartz 实现Quartz的一些日志文件及目录初始化工作
/// <summary> /// Quartz日志文件、目录初始化与操作日志写入 /// </summary> public class FileQuartz { private static string _rootPath { get; set; } private static string _logPath { get; set; } /// <summary> /// 创建作业所在根目录及日志文件夹 /// </summary> /// <returns></returns> public static string CreateQuartzRootPath(IWebHostEnvironment 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); } } /// <summary> /// 获取日志 /// </summary> /// <param name="taskName">任务名称</param> /// <param name="groupName">组名称</param> /// <param name="page">第几页</param> /// <param name="pageSize">显示条数</param> /// <returns></returns> 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(); } /// <summary> /// 持久化 /// </summary> /// <param name="taskList"></param> public static void WriteJobConfig(List<TaskOptions> taskList) { string jobs = JsonConvert.SerializeObject(taskList); //写入配置文件 FileHelper.WriteFile(_rootPath, QuartzFileInfo.JobConfigFileName, jobs,false); } /// <summary> /// 写入日志 /// </summary> /// <param name="content"></param> 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; } } }
添加一个文件监听类FileWatcher.cs
/// <summary> /// 文件监听 /// </summary> public class FileWatcher { static FileSystemWatcher watcher = new FileSystemWatcher(); private static Action action; private static DateTime lastRead = DateTime.MinValue; /// <summary> /// 初始化监听 /// </summary> /// <param name="StrWarcherPath">需要监听的目录</param> /// <param name="FilterType">需要监听的文件类型(筛选器字符串)</param> /// <param name="IsEnableRaising">是否启用监听</param> /// <param name="IsInclude">是否监听子目录</param> public static void WatcherStrat(string StrWarcherPath, string FilterType, bool IsEnableRaising, bool IsInclude, Action method = null) { //初始化监听 //watcher.BeginInit(); //设置监听文件类型 watcher.Filter = FilterType; //设置是否监听子目录 watcher.IncludeSubdirectories = IsInclude; //设置需要监听的更改类型(如:文件或者文件夹的属性,文件或者文件夹的创建时间;NotifyFilters枚举的内容) watcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size; //设置监听的路径 watcher.Path = StrWarcherPath; //注册创建文件或目录时的监听事件 //watcher.Created += new FileSystemEventHandler(watch_created); //注册当指定目录的文件或者目录发生改变的时候的监听事件 watcher.Changed += new FileSystemEventHandler(watch_changed); //注册当删除目录的文件或者目录的时候的监听事件 watcher.Deleted += new FileSystemEventHandler(watch_deleted); //当指定目录的文件或者目录发生重命名的时候的监听事件 watcher.Renamed += new RenamedEventHandler(watch_renamed); //设置是否启用监听? watcher.EnableRaisingEvents = IsEnableRaising; action = method; //结束初始化 //watcher.EndInit(); } /// <summary> /// 创建文件或者目录时的监听事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void watch_created(object sender, FileSystemEventArgs e) { //事件内容 output("create:" + e.FullPath); } /// <summary> /// 当指定目录的文件或者目录发生改变的时候的监听事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void watch_changed(object sender, FileSystemEventArgs e) { var now = DateTime.Now; var lastWriteTime = File.GetLastWriteTime(e.FullPath); if (now == lastWriteTime) { return; } if (lastWriteTime != lastRead) { // do something... action?.Invoke(); //事件内容 output("change:" + e.FullPath); lastRead = lastWriteTime; } } /// <summary> /// 当删除目录的文件或者目录的时候的监听事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void watch_deleted(object sender, FileSystemEventArgs e) { //事件内容 output("del:" + e.FullPath); } /// <summary> /// 当指定目录的文件或者目录发生重命名的时候的事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void watch_renamed(object sender, RenamedEventArgs e) { //事件内容 output("rename:" + e.FullPath); } /// <summary> /// 启动或者停止监听 /// </summary> /// <param name="IsEnableRaising">True:启用监听,False:关闭监听</param> private void WatchStartOrSopt(bool IsEnableRaising) { watcher.EnableRaisingEvents = IsEnableRaising; } private static void output(string text) { //FileStream fs = new FileStream("D:\\listen.txt", FileMode.Append); //StreamWriter sw = new StreamWriter(fs, Encoding.Default); //sw.WriteLine(text); //sw.Close(); //fs.Close(); //files.Add(text); Debug.WriteLine(text); } }
然后扩展下Quartz
/// <summary> /// Quartz扩展类,实现增,改、删,查任务操作等 /// </summary> public static class QuartzNETExtension { private static List<TaskOptions> _taskList = new List<TaskOptions>(); private static IServiceProvider services; private static ISchedulerFactory _schedulerFactory; /// <summary> /// 文件监听状态 当值为true时是文件监听 /// </summary> private static bool fileWatcher = false; /// <summary> /// 初始化作业 /// </summary> /// <param name="applicationBuilder"></param> /// <param name="env"></param> /// <returns></returns> public static IApplicationBuilder UseQuartz(this IApplicationBuilder applicationBuilder, IWebHostEnvironment env) { services = applicationBuilder.ApplicationServices; _schedulerFactory = services.GetService<ISchedulerFactory>(); //创建作业文件 string path = FileQuartz.CreateQuartzRootPath(env); string jobConfig = FileHelper.ReadFile(path + QuartzFileInfo.JobConfigFileName); #region 启用文件监听 //创建后台工作线程 Thread watcher = new Thread(new ParameterizedThreadStart(FileWatcherChanged)); watcher.IsBackground = true;//设置为后台线程 watcher.Start(new { path }); #endregion if (string.IsNullOrEmpty(jobConfig)) { FileHelper.WriteFile(FileQuartz.LogPath, "start.txt", $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},没有默认配置任务\r\n", true); return applicationBuilder; } int errorCount = 0; string errorMsg = ""; TaskOptions options = null; try { _taskList = JsonConvert.DeserializeObject<List<TaskOptions>>(jobConfig); _taskList.ForEach(x => { options = x; var result = x.AddJob(_schedulerFactory, true, jobFactory: services.GetService<IJobFactory>()).GetAwaiter().GetResult(); }); } catch (Exception ex) { errorCount = +1; errorMsg += $"作业:{options?.TaskName},异常:{ex.Message}"; } string content = $"成功:{ _taskList.Count - errorCount}个,失败{errorCount}个,异常:{errorMsg}\r\n"; FileQuartz.WriteStartLog(content); return applicationBuilder; } /// <summary> /// 获取所有的作业 /// </summary> /// <param name="schedulerFactory"></param> /// <returns></returns> public static async Task<List<TaskOptions>> GetJobs(this ISchedulerFactory schedulerFactory) { List<TaskOptions> list = new List<TaskOptions>(); try { IScheduler _scheduler = await schedulerFactory.GetScheduler(); var groups = await _scheduler.GetJobGroupNames(); foreach (var groupName in groups) { foreach (var jobKey in await _scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(groupName))) { TaskOptions taskOptions = _taskList.Where(x => x.GroupName == jobKey.Group && x.TaskName == jobKey.Name) .FirstOrDefault(); if (taskOptions == null) continue; var triggers = await _scheduler.GetTriggersOfJob(jobKey); foreach (ITrigger trigger in triggers) { DateTimeOffset? dateTimeOffset = trigger.GetPreviousFireTimeUtc(); if (dateTimeOffset != null) { taskOptions.LastRunTime = Convert.ToDateTime(dateTimeOffset.ToString()); } else { var runlog = FileQuartz.GetJobRunLog(taskOptions.TaskName, taskOptions.GroupName, 1, 2); if (runlog.Count > 0) { DateTime.TryParse(runlog[0].BeginDate, out DateTime lastRunTime); taskOptions.LastRunTime = lastRunTime; } } } list.Add(taskOptions); } } } catch (Exception ex) { FileQuartz.WriteStartLog("获取作业异常:" + ex.Message + ex.StackTrace); } return list; } /// <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, IJobFactory jobFactory = null) { 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); if (fileWatcher != true) FileQuartz.WriteJobConfig(_taskList); } IJobDetail job = JobBuilder.Create<CreateJob>() .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(); if (jobFactory != null) { scheduler.JobFactory = jobFactory; } 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.add, 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.del, 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.update, 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.pause, 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.open, 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.run, taskOptions); } /// <summary> /// 写入配置文件 /// </summary> /// <param name="taskOptions"></param> /// <param name="schedulerFactory"></param> /// <param name="action"></param> /// <returns></returns> public static object ModifyTaskEntity(this TaskOptions taskOptions, ISchedulerFactory schedulerFactory, JobAction action) { TaskOptions options = null; object result = null; switch (action) { case JobAction.del: 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.update: 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.pause: case JobAction.open: case JobAction.stop: case JobAction.run: options = _taskList.Where(x => x.TaskName == taskOptions.TaskName && x.GroupName == taskOptions.GroupName).FirstOrDefault(); if (action == JobAction.pause) { options.Status = (int)TriggerState.Paused; } else if (action == JobAction.run) { 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.del: case JobAction.update: await scheduler.PauseTrigger(trigger.Key); await scheduler.UnscheduleJob(trigger.Key);// 移除触发器 await scheduler.DeleteJob(trigger.JobKey); result = taskOptions.ModifyTaskEntity(schedulerFactory, action); break; case JobAction.pause: case JobAction.stop: case JobAction.open: result = taskOptions.ModifyTaskEntity(schedulerFactory, action); if (action == JobAction.pause) { //暂停 await scheduler.PauseTrigger(trigger.Key); } else if (action == JobAction.open) { //恢复 await scheduler.ResumeTrigger(trigger.Key); // await scheduler.RescheduleJob(trigger.Key, trigger); } else { //停止 await scheduler.Shutdown(); } break; case JobAction.run: //执行 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); } } /// <summary> /// 获取当前要执行的任务事件 /// </summary> /// <param name="context"></param>通过作业上下文获取作业对应的配置参数 /// <returns></returns> public static TaskOptions GetTaskOptions(this IJobExecutionContext context) { AbstractTrigger trigger = (context as JobExecutionContextImpl).Trigger as AbstractTrigger; TaskOptions taskOptions = _taskList.Where(x => x.TaskName == trigger.Name && x.GroupName == trigger.Group).FirstOrDefault(); return taskOptions ?? _taskList.Where(x => x.TaskName == trigger.JobName && x.GroupName == trigger.JobGroup).FirstOrDefault(); } /// <summary> /// 清除所有任务 /// </summary> /// <param name="schedulerFactory"></param> public static async void ClearJob(this ISchedulerFactory schedulerFactory) { IScheduler scheduler = await schedulerFactory.GetScheduler(); await scheduler.Clear(); } /// <summary> /// 作业是否存在 /// </summary> /// <param name="taskOptions"></param> /// <param name="init">初始化的不需要判断</param> /// <returns></returns> public static (bool, object) Exists(this TaskOptions taskOptions, bool init) { if (!init && _taskList.Any(x => x.TaskName == taskOptions.TaskName && x.GroupName == taskOptions.GroupName)) { return (false, new { status = false, msg = $"作业:{taskOptions.TaskName},分组:{taskOptions.GroupName}已经存在" }); } return (true, null); } public static (bool, string) IsValidExpression(this string cronExpression) { try { CronTriggerImpl trigger = new CronTriggerImpl(); trigger.CronExpressionString = cronExpression; DateTimeOffset? date = trigger.ComputeFirstFireTimeUtc(null); return (date != null, date == null ? $"请确认表达式{cronExpression}是否正确!" : ""); } catch (Exception e) { return (false, $"请确认表达式{cronExpression}是否正确!{e.Message}"); } } private static void FileWatcherChanged(object obj) { string filePath = obj.GetType().GetProperty("path").GetValue(obj).ToString(); FileWatcher.WatcherStrat(filePath, "*.json", true, true, () => { try { fileWatcher = true; Thread.Sleep(1000); string jobConfig = FileHelper.ReadFile(filePath + QuartzFileInfo.JobConfigFileName); var taskList = JsonConvert.DeserializeObject<List<TaskOptions>>(jobConfig).Where(s=>s.Status==0).ToList(); if (taskList.Count <= 0) return; TaskOptions options = null; _schedulerFactory.ClearJob(); taskList.ForEach(x => { options = x; x.AddJob(_schedulerFactory, true, jobFactory: services.GetService<IJobFactory>()).GetAwaiter().GetResult(); }); //重新给值 _taskList = taskList; } catch (Exception ex) { throw ex; } }); } }
新建一个CreateJob继承IJob实现任务操作
/// <summary> /// 执行事件操作 /// </summary> public class CreateJob : IJob { //readonly IHttpClientFactory httpClientFactory; /// <summary> /// 2020.05.31增加构造方法 /// </summary> /// <param name="serviceProvider"></param> /// <param name="httpClientFactory"></param> public CreateJob(IServiceProvider serviceProvider) { //serviceProvider.GetService() } public async Task Execute(IJobExecutionContext context) { DateTime dateTime = DateTime.Now; TaskOptions taskOptions = context.GetTaskOptions(); string httpMessage = ""; AbstractTrigger trigger = (context as JobExecutionContextImpl).Trigger as AbstractTrigger; if (taskOptions == null) { FileHelper.WriteFile(FileQuartz.LogPath + trigger.Group, $"{trigger.Name}.txt", "未到找作业或可能被移除", true); return; } Console.WriteLine($"作业[{taskOptions.TaskName}]开始:{ DateTime.Now.ToString("yyyy-MM-dd HH:mm:sss")}"); try { if (taskOptions.JobType == 1) { if (string.IsNullOrEmpty(taskOptions.ApiUrl) || taskOptions.ApiUrl == "/") { FileHelper.WriteFile(FileQuartz.LogPath + trigger.Group, $"{trigger.Name}.txt", $"{ DateTime.Now.ToString("yyyy-MM-dd HH:mm:sss")}未配置url,", true); return; } Dictionary<string, string> header = new Dictionary<string, string>(); if (!string.IsNullOrEmpty(taskOptions.AuthKey) && !string.IsNullOrEmpty(taskOptions.AuthValue)) { header.Add(taskOptions.AuthKey.Trim(), taskOptions.AuthValue.Trim()); } RestApi<string> restApi = new RestApi<string>(); httpMessage = taskOptions.RequestType?.ToLower() == "get" ? restApi.Get(taskOptions.ApiUrl, null, header) : restApi.Post(taskOptions.ApiUrl, null, header); //await httpClientFactory.HttpSendAsync( // taskOptions.RequestType?.ToLower() == "get" ? HttpMethod.Get : HttpMethod.Post, // taskOptions.ApiUrl, // header); } else { if (string.IsNullOrEmpty(taskOptions.AssemblyName)) { FileHelper.WriteFile(FileQuartz.LogPath + trigger.Group, $"{trigger.Name}.txt", $"{ DateTime.Now.ToString("yyyy-MM-dd HH:mm:sss")}未配置程序集名称,", true); return; } if (string.IsNullOrEmpty(taskOptions.ClassName)) { FileHelper.WriteFile(FileQuartz.LogPath + trigger.Group, $"{trigger.Name}.txt", $"{ DateTime.Now.ToString("yyyy-MM-dd HH:mm:sss")}未配置类名称,", true); return; } if (string.IsNullOrEmpty(taskOptions.MethodName)) { FileHelper.WriteFile(FileQuartz.LogPath + trigger.Group, $"{trigger.Name}.txt", $"{ DateTime.Now.ToString("yyyy-MM-dd HH:mm:sss")}未配置方法名称,", true); return; } Assembly assembly = GetAssemblyByName(taskOptions.AssemblyName); Type getClass = assembly.GetTypes().Where(a => a.Name == taskOptions.ClassName).ToList()[0]; //创建对象 object obj = Activator.CreateInstance(getClass); //获取方法 MethodInfo meth = getClass.GetMethod(taskOptions.MethodName); //设置参数,如果没有设置 null,调用方法 meth.Invoke(obj, null); httpMessage = "执行方法成功"; } } catch (Exception ex) { httpMessage = ex.Message; } try { string logContent = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}_{dateTime.ToString("yyyy-MM-dd HH:mm:ss")}_{(string.IsNullOrEmpty(httpMessage) ? "OK" : httpMessage)}\r\n"; FileHelper.WriteFile(FileQuartz.LogPath + taskOptions.GroupName + "\\", $"{taskOptions.TaskName}.txt", logContent, true); } catch (Exception) { } Console.WriteLine(trigger.FullName + " " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:sss") + " " + httpMessage); return; } //通过程序集的名称加载程序集 public static Assembly GetAssemblyByName(string assemblyName) { return AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName)); } }
新一个 TaskOptions 类 定义一些任务需要的东西
/// <summary> /// 任务实体选择类 /// </summary> public class TaskOptions { /// <summary> /// 任务名称 /// </summary> public string TaskName { get; set; } /// <summary> /// 分组名称 /// </summary> public string GroupName { get; set; } /// <summary> /// 时间 (Cron 表达式 https://cron.qqe2.com/) /// </summary> public string Interval { get; set; } /// <summary> /// 请求的url /// </summary> public string ApiUrl { get; set; } /// <summary> /// 认证key /// </summary> public string AuthKey { get; set; } /// <summary> /// 认证value /// </summary> public string AuthValue { get; set; } /// <summary> /// 说明 /// </summary> public string Describe { get; set; } /// <summary> /// 请求头 /// </summary> public string RequestType { get; set; } /// <summary> /// 最后执行时间 /// </summary> public DateTime? LastRunTime { get; set; } /// <summary> /// 状态 /// </summary> public int Status { get; set; } /// <summary> /// 程序集名称 /// </summary> public string AssemblyName { get; set; } /// <summary> /// 类名称 /// </summary> public string ClassName { get; set; } /// <summary> /// 方法名称 /// </summary> public string MethodName { get; set; } /// <summary> /// 任务类型(1、执行url 2、执行控制器) /// </summary> public int JobType { get; set; } } public class TaskLog { public string BeginDate { get; set; } public string EndDate { get; set; } public string Msg { get; set; } }
新建一个 IOCJobFactory 继承 IJobFactory 实现依赖注入
/// <summary> /// 实现任务实例创建的依赖注入 /// </summary> public class IOCJobFactory : IJobFactory { /// <summary> /// 容器提供器, /// </summary> private readonly IServiceProvider _serviceProvider; /// <summary> /// 构造函数 /// </summary> /// <param name="serviceProvider"></param> public IOCJobFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } /// <summary> /// 返回IJob /// </summary> /// <param name="bundle"></param> /// <param name="scheduler"></param> /// <returns></returns> public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) { return _serviceProvider.GetService(bundle.JobDetail.JobType) as IJob; } /// <summary> /// 清理销毁IJob /// </summary> /// <param name="job"></param> public void ReturnJob(IJob job) { (job as IDisposable)?.Dispose(); } }
JobAction枚举类 (Desc这个是自己扩展枚举)
public enum JobAction { [Desc("新增")] add = 1, [Desc("删除")] del = 2, [Desc("修改")] update = 3, [Desc("暂停")] pause = 4, [Desc("停止")] stop = 5, [Desc("开启")] open = 6, [Desc("立即执行")] run = 7 }
路径/转换
public static class ConvertPath { public static bool _windows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); public static string ReplacePath(this string path) { if (string.IsNullOrEmpty(path)) return ""; if (_windows) return path.Replace("/", "\\"); return path.Replace("\\", "/"); } }
配置注入:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { //初始化任务 app.UseQuartz(env); app.UseRouting(); } public void ConfigureServices(IServiceCollection services) { services.AddTransient<CreateJob>(); services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>(); services.AddSingleton<Quartz.Spi.IJobFactory, IOCJobFactory>(); }
使用:
[Autowired] private ILogger<TestController> _logger; [Autowired] private ISchedulerFactory _schedulerFactory; [Autowired] private IJobFactory _jobFactory; public QuartzController(AutowiredService autowiredService) { //this._logger = logger; autowiredService.Autowired(this); } /// <summary> /// 获取所有的作业 /// </summary> /// <returns></returns> [AllowAnonymous] [HttpGet("GetJobs")] public async Task<ApiResult> GetJobs() { return new ApiResult(ResultCode.SUCCESS, await _schedulerFactory.GetJobs()); } /// <summary> /// 获取作业运行日志 /// </summary> /// <param name="taskName"></param> /// <param name="groupName"></param> /// <param name="page"></param> /// <returns></returns> [AllowAnonymous] [HttpGet("GetRunLog")] public ApiResult GetRunLog(string taskName, string groupName, int page = 1) { return new ApiResult(ResultCode.SUCCESS, FileQuartz.GetJobRunLog(taskName, groupName, page)); } /// <summary> /// 添加任务 /// </summary> /// <param name="taskOptions"></param> /// <returns></returns> [AllowAnonymous] [HttpPost("Add")] public async Task<ApiResult> Add(TaskOptions taskOptions) { return new ApiResult(ResultCode.SUCCESS, await taskOptions.AddJob(_schedulerFactory, jobFactory: _jobFactory)); } [AllowAnonymous] [HttpDelete("Remove")] public async Task<ApiResult> Remove(TaskOptions taskOptions) { return new ApiResult(ResultCode.SUCCESS, await _schedulerFactory.Remove(taskOptions)); } [AllowAnonymous] [HttpPut("Update")] public async Task<ApiResult> Update(TaskOptions taskOptions) { return new ApiResult(ResultCode.SUCCESS, await _schedulerFactory.Update(taskOptions)); } [AllowAnonymous] [HttpPost("Pause")] public async Task<ApiResult> Pause(TaskOptions taskOptions) { return new ApiResult(ResultCode.SUCCESS, await _schedulerFactory.Pause(taskOptions)); } [AllowAnonymous] [HttpPost("Start")] public async Task<ApiResult> Start(TaskOptions taskOptions) { return new ApiResult(ResultCode.SUCCESS, await _schedulerFactory.Start(taskOptions)); } [AllowAnonymous] [HttpPost("Run")] public async Task<ApiResult> Run(TaskOptions taskOptions) { return new ApiResult(ResultCode.SUCCESS, await _schedulerFactory.Run(taskOptions)); }
[Autowired]
private ILogger<TestController> _logger;
[Autowired]
private ISchedulerFactory _schedulerFactory;
[Autowired]
private IJobFactory _jobFactory;
public QuartzController(AutowiredService autowiredService)
{
//this._logger = logger;
autowiredService.Autowired(this);
}
这段需要改用下面这段
private readonly ISchedulerFactory _schedulerFactory;
private readonly IJobFactory _jobFactory;
public QuartzController(ISchedulerFactory schedulerFactory, IJobFactory jobFactory)
{
this._jobFactory = jobFactory;
this._schedulerFactory = schedulerFactory;
}
Quartz目前支持三种方式运行定时任务:1、是通过请求Url 方式调用 2、是通过程序集调用 3、修改持久化json文件实现任务增删
评论区