.net core 3 使用Quartz 3.0并实现任务持久化文件监听

首先新建一个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文件实现任务增删


本文作者:admin

本文链接:https://www.javalc.com/post/31.html

版权声明:本篇文章于2020-10-27,由admin发表,转载请注明出处:分享你我。如有疑问,请联系我们

解决VS 无法连接到Web服务器"IIS Express"

发表评论

取消
扫码支持