引入Autofac、Autofac.Extras.Quartz
新建一个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 ISchedulerFactory _schedulerFactory;
/// <summary>
/// 文件监听状态 当值为true时是文件监听
/// </summary>
private static bool fileWatcher = false;
/// <summary>
/// 初始化作业
/// </summary>
/// <param name="applicationBuilder"></param>
/// <param name="env"></param>
/// <returns></returns>
public static void UseQuartz(this ISchedulerFactory schedulerFactory)
{
_schedulerFactory = schedulerFactory;
//创建作业文件
string path = FileQuartz.CreateQuartzRootPath();
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;
}
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: AutofacBuilder.GetFromFac<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);
}
/// <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)
.WithDescription(taskOptions.Describe)
.WithCronSchedule(taskOptions.Interval)
.StartNow()
.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: AutofacBuilder.GetFromFac<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; }
}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("\\", "/");
}
}新建一个AutofacBuilder类
/// <summary>
/// Autofac 依赖注入
/// </summary>
public class AutofacBuilder
{
private static IContainer _container;
public static void instance()
{
ContainerBuilder builder = new ContainerBuilder();
// 配置quartz.net依赖注入 && 注册定时任务模块 && 注册AutofacJobFactory(IJobFactory)
builder.RegisterModule(new QuartzAutofacFactoryModule());
builder.RegisterModule(new QuartzAutofacJobsModule(typeof(CreateJob).Assembly));
_container = builder.Build(); //只有在Build之后,才能调用GetFromFac
//持久化中初始化定时任务
AutofacBuilder.GetFromFac<ISchedulerFactory>().UseQuartz();
}
/// <summary>
/// 从IOC容器内取回指定的对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetFromFac<T>()
{
try
{
if (_container == null)
instance(); return _container.Resolve<T>();
}
catch (Exception ex)
{
throw;
}
}
public void Dispose()
{
_container.Dispose();
GC.SuppressFinalize(this);
}
}配置ioc注入初始化工作:
AutofacBuilder.instance();
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
//windows服务初始化工作
AutofacBuilder.instance();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new electron());
}
}private readonly ISchedulerFactory _schedulerFactory=AutofacBuilder.GetFromFac<ISchedulerFactory >();
private readonly IJobFactory _jobFactory=AutofacBuilder.GetFromFac<IJobFactory>();
await _schedulerFactory.(扩展的方法)
Quartz目前支持三种方式运行定时任务:1、是通过请求Url 方式调用 2、是通过程序集调用 3、修改持久化json文件实现任务增删
评论区