You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DSWMS/Quartz.NetUI/Quartz.NET.Web/Extensions/QuartzNETExtension.cs

428 lines
18 KiB
C#

2 years ago
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Quartz.Impl;
using Quartz.Impl.Matchers;
using Quartz.Impl.Triggers;
using Quartz.NET.Web.Constant;
using Quartz.NET.Web.Enum;
using Quartz.NET.Web.Models;
using Quartz.NET.Web.Utility;
using Quartz.Spi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Quartz.NET.Web.Extensions
{
public static class QuartzNETExtension
{
private static List<TaskOptions> _taskList = new List<TaskOptions>();
/// <summary>
/// 初始化作业
/// </summary>
/// <param name="applicationBuilder"></param>
/// <param name="env"></param>
/// <returns></returns>
public static IApplicationBuilder UseQuartz(this IApplicationBuilder applicationBuilder, IWebHostEnvironment env)
{
IServiceProvider services = applicationBuilder.ApplicationServices;
ISchedulerFactory _schedulerFactory = services.GetService<ISchedulerFactory>();
string path = FileQuartz.CreateQuartzRootPath(env);
string jobConfig = FileHelper.ReadFile(path + QuartzFileInfo.JobConfigFileName);
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);
FileQuartz.WriteJobConfig(_taskList);
}
IJobDetail job = JobBuilder.Create<HttpResultfulJob>()
.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)
{
try
{
jobFactory = HttpContext.Current.RequestServices.GetService<IJobFactory>();
}
catch (Exception ex)
{
Console.WriteLine($"创建任务[{taskOptions.TaskName}]异常,{ex.Message}");
}
}
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., taskOptions.TaskName, taskOptions.GroupName);
}
catch (Exception ex)
{
return new { status = false, msg = ex.Message };
}
return new { status = true };
}
/// <summary>
/// 移除作业
/// </summary>
/// <param name="schedulerFactory"></param>
/// <param name="taskName"></param>
/// <param name="groupName"></param>
/// <returns></returns>
public static Task<object> Remove(this ISchedulerFactory schedulerFactory, TaskOptions taskOptions)
{
return schedulerFactory.TriggerAction(taskOptions.TaskName, taskOptions.GroupName, JobAction., taskOptions);
}
/// <summary>
/// 更新作业
/// </summary>
/// <param name="schedulerFactory"></param>
/// <param name="taskOptions"></param>
/// <returns></returns>
public static Task<object> Update(this ISchedulerFactory schedulerFactory, TaskOptions taskOptions)
{
return schedulerFactory.TriggerAction(taskOptions.TaskName, taskOptions.GroupName, JobAction., taskOptions);
}
/// <summary>
/// 暂停作业
/// </summary>
/// <param name="schedulerFactory"></param>
/// <param name="taskOptions"></param>
/// <returns></returns>
public static Task<object> Pause(this ISchedulerFactory schedulerFactory, TaskOptions taskOptions)
{
return schedulerFactory.TriggerAction(taskOptions.TaskName, taskOptions.GroupName, JobAction., taskOptions);
}
/// <summary>
/// 启动作业
/// </summary>
/// <param name="schedulerFactory"></param>
/// <param name="taskOptions"></param>
/// <returns></returns>
public static Task<object> Start(this ISchedulerFactory schedulerFactory, TaskOptions taskOptions)
{
return schedulerFactory.TriggerAction(taskOptions.TaskName, taskOptions.GroupName, JobAction., taskOptions);
}
/// <summary>
/// 立即执行一次作业
/// </summary>
/// <param name="schedulerFactory"></param>
/// <param name="taskOptions"></param>
/// <returns></returns>
public static Task<object> Run(this ISchedulerFactory schedulerFactory, TaskOptions taskOptions)
{
return schedulerFactory.TriggerAction(taskOptions.TaskName, taskOptions.GroupName, JobAction., taskOptions);
}
public static object ModifyTaskEntity(this TaskOptions taskOptions, ISchedulerFactory schedulerFactory, JobAction action)
{
TaskOptions options = null;
object result = null;
switch (action)
{
case JobAction.:
for (int i = 0; i < _taskList.Count; i++)
{
options = _taskList[i];
if (options.TaskName == taskOptions.TaskName && options.GroupName == taskOptions.GroupName)
{
_taskList.RemoveAt(i);
}
}
break;
case JobAction.:
options = _taskList.Where(x => x.TaskName == taskOptions.TaskName && x.GroupName == taskOptions.GroupName).FirstOrDefault();
//移除以前的配置
if (options != null)
{
_taskList.Remove(options);
}
//生成任务并添加新配置
result = taskOptions.AddJob(schedulerFactory, false).GetAwaiter().GetResult();
break;
case JobAction.:
case JobAction.:
case JobAction.:
case JobAction.:
options = _taskList.Where(x => x.TaskName == taskOptions.TaskName && x.GroupName == taskOptions.GroupName).FirstOrDefault();
if (action == JobAction.)
{
options.Status = (int)TriggerState.Paused;
}
else if (action == JobAction.)
{
options.Status = (int)action;
}
else
{
options.Status = (int)TriggerState.Normal;
}
break;
}
//生成配置文件
FileQuartz.WriteJobConfig(_taskList);
FileQuartz.WriteJobAction(action, taskOptions.TaskName, taskOptions.GroupName, "操作对象:" + JsonConvert.SerializeObject(taskOptions));
return result;
}
/// <summary>
/// 触发新增、删除、修改、暂停、启用、立即执行事件
/// </summary>
/// <param name="schedulerFactory"></param>
/// <param name="taskName"></param>
/// <param name="groupName"></param>
/// <param name="action"></param>
/// <param name="taskOptions"></param>
/// <returns></returns>
public static async Task<object> TriggerAction(this ISchedulerFactory schedulerFactory, string taskName, string groupName, JobAction action, TaskOptions taskOptions = null)
{
string errorMsg = "";
try
{
IScheduler scheduler = await schedulerFactory.GetScheduler();
List<JobKey> jobKeys = scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(groupName)).Result.ToList();
if (jobKeys == null || jobKeys.Count() == 0)
{
errorMsg = $"未找到分组[{groupName}]";
return new { status = false, msg = errorMsg };
}
JobKey jobKey = jobKeys.Where(s => scheduler.GetTriggersOfJob(s).Result.Any(x => (x as CronTriggerImpl).Name == taskName)).FirstOrDefault();
if (jobKey == null)
{
errorMsg = $"未找到触发器[{taskName}]";
return new { status = false, msg = errorMsg };
}
var triggers = await scheduler.GetTriggersOfJob(jobKey);
ITrigger trigger = triggers?.Where(x => (x as CronTriggerImpl).Name == taskName).FirstOrDefault();
if (trigger == null)
{
errorMsg = $"未找到触发器[{taskName}]";
return new { status = false, msg = errorMsg };
}
object result = null;
switch (action)
{
case JobAction.:
case JobAction.:
await scheduler.PauseTrigger(trigger.Key);
await scheduler.UnscheduleJob(trigger.Key);// 移除触发器
await scheduler.DeleteJob(trigger.JobKey);
result = taskOptions.ModifyTaskEntity(schedulerFactory, action);
break;
case JobAction.:
case JobAction.:
case JobAction.:
result = taskOptions.ModifyTaskEntity(schedulerFactory, action);
if (action == JobAction.)
{
await scheduler.PauseTrigger(trigger.Key);
}
else if (action == JobAction.)
{
await scheduler.ResumeTrigger(trigger.Key);
// await scheduler.RescheduleJob(trigger.Key, trigger);
}
else
{
await scheduler.Shutdown();
}
break;
case JobAction.:
await scheduler.TriggerJob(jobKey);
break;
}
return result ?? new { status = true, msg = $"作业{action.ToString()}成功" };
}
catch (Exception ex)
{
errorMsg = ex.Message;
return new { status = false, msg = ex.Message };
}
finally
{
FileQuartz.WriteJobAction(action, taskName, groupName, errorMsg);
}
}
/// <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="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}");
}
}
}
}