/******************************************************************************* * Copyright © 2020 HT.Cloud.Framework 版权所有 * Author: HT.Cloud * Description: WaterCloud快速开发平台 * Website: *********************************************************************************/ using Quartz; using Quartz.Impl.Triggers; using Quartz.Spi; using SqlSugar; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Reflection; using System.Threading.Tasks; using HT.Cloud.Code; using HT.Cloud.DataBase; using HT.Cloud.Domain.SystemSecurity; using HT.Cloud.Service.AutoJob; namespace HT.Cloud.Service.SystemSecurity { public class OpenJobsService : IDenpendency { private RepositoryBase repository; private IScheduler _scheduler; private HttpWebClient _httpClient; public OpenJobsService(ISqlSugarClient context, ISchedulerFactory schedulerFactory, IJobFactory iocJobfactory, IHttpClientFactory httpClient) { repository = new RepositoryBase(context); _scheduler = schedulerFactory.GetScheduler().GetAwaiter().GetResult(); _scheduler.JobFactory = iocJobfactory; _httpClient = new HttpWebClient(httpClient); } /// /// 加载列表 /// public async Task> GetLookList(Pagination pagination, string keyword = "") { var DbNumber = OperatorProvider.Provider.GetCurrent().DbNumber; var query = repository.IQueryable().Where(a => a.F_DbNumber == DbNumber); if (!string.IsNullOrEmpty(keyword)) { query = query.Where(a => a.F_JobName.Contains(keyword) || a.F_Description.Contains(keyword)); } query = query.Where(a => a.F_DeleteMark == false); return await query.ToPageListAsync(pagination); } public async Task> GetLogList(string keyValue) { return await repository.Db.Queryable().Where(a => a.F_JobId == keyValue).OrderBy(a => a.F_CreatorTime, OrderByType.Desc).ToListAsync(); } public async Task> GetList(string keyword = "") { var DbNumber = OperatorProvider.Provider.GetCurrent().DbNumber; var query = repository.IQueryable().Where(a => a.F_DbNumber == DbNumber); if (!string.IsNullOrEmpty(keyword)) { query = query.Where(a => a.F_JobName.Contains(keyword)); } return await query.Where(a => a.F_DeleteMark == false).ToListAsync(); } public async Task> GetAllList(string keyword = "") { var query = repository.IQueryable(); if (!string.IsNullOrEmpty(keyword)) { query = query.Where(a => a.F_JobName.Contains(keyword)); } return await query.Where(a => a.F_DeleteMark == false).ToListAsync(); } public async Task GetForm(string keyValue) { var data = await repository.FindEntity(keyValue); return data; } public async Task SubmitForm(OpenJobEntity entity, string keyValue) { bool IsTrue = CronExpression.IsValidExpression(entity.F_CronExpress); if (IsTrue == false) { throw new Exception("定时任务的Cron表达式不正确!"); } repository.Db.Ado.BeginTran(); if (!string.IsNullOrEmpty(keyValue)) { entity.Modify(keyValue); await repository.Update(entity); } else { entity.Create(); entity.F_DbNumber = OperatorProvider.Provider.GetCurrent().DbNumber; await repository.Insert(entity); } //启动任务 if (entity.F_DoItNow == true) { await ChangeJobStatus(entity.F_Id, 1); } repository.Db.Ado.CommitTran(); //执行任务 if (entity.F_DoItNow == true) { await DoNow(entity.F_Id, false); } } /// /// 清除任务计划 /// /// public async Task ClearScheduleJob() { try { await _scheduler.Clear(); } catch (Exception ex) { LogHelper.WriteWithTime(ex); } } public async Task DeleteForm(string keyValue) { var job = await repository.FindEntity(keyValue); TriggerKey triggerKey = new TriggerKey(job.F_JobName, job.F_JobGroup); await _scheduler.PauseTrigger(triggerKey); await _scheduler.UnscheduleJob(triggerKey); await _scheduler.DeleteJob(new JobKey(job.F_JobName, job.F_JobGroup)); await repository.Delete(a => a.F_Id == keyValue); } #region 定时任务运行相关操作 /// /// 返回系统的job接口 /// /// public List QueryLocalHandlers() { var types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(a => a.GetTypes().Where(a => a.GetInterfaces() .Contains(typeof(IJobTask)))) .ToArray(); var list = new List(); foreach (var item in types) { list.Add(new KeyValue { Key = item.FullName, Description = item.GetCustomAttribute(false)!.ClassDescription }); } return list; } public async Task ChangeJobStatus(string keyValue, int status) { var job = await repository.FindEntity(a => a.F_Id == keyValue); if (job == null) { throw new Exception("任务不存在"); } if (status == 0) //停止 { TriggerKey triggerKey = new TriggerKey(job.F_JobName, job.F_JobGroup); // 停止触发器 await _scheduler.PauseTrigger(triggerKey); // 移除触发器 await _scheduler.UnscheduleJob(triggerKey); // 删除任务 await _scheduler.DeleteJob(new JobKey(job.F_JobName, job.F_JobGroup)); job.F_EnabledMark = false; job.F_EndRunTime = DateTime.Now; } else //启动 { DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(job.F_StarRunTime, 1); DateTimeOffset endRunTime = DateBuilder.NextGivenSecondDate(DateTime.MaxValue.AddDays(-1), 1); ITrigger trigger = TriggerBuilder.Create() .StartAt(starRunTime) .EndAt(endRunTime) .WithIdentity(job.F_JobName, job.F_JobGroup) .WithCronSchedule(job.F_CronExpress) .Build(); ((CronTriggerImpl)trigger).MisfireInstruction = MisfireInstruction.CronTrigger.DoNothing; // 判断数据库中有没有记录过,有的话,quartz会自动从数据库中提取信息创建 schedule if (!await _scheduler.CheckExists(new JobKey(job.F_JobName, job.F_JobGroup))) { IJobDetail jobdetail = JobBuilder.Create().WithIdentity(job.F_JobName, job.F_JobGroup).Build(); jobdetail.JobDataMap.Add("F_Id", job.F_Id); await _scheduler.ScheduleJob(jobdetail, trigger); } job.F_EnabledMark = true; job.F_StarRunTime = DateTime.Now; } job.Modify(job.F_Id); await repository.Update(job); } public async Task DoNow(string keyValue, bool returnEx = true) { try { // 获取数据库中的任务 var dbJobEntity = await GetForm(keyValue); if (dbJobEntity != null) { DateTime now = DateTime.Now; #region 执行任务 OpenJobLogEntity log = new OpenJobLogEntity(); log.F_Id = Utils.GuId(); log.F_JobId = keyValue; log.F_JobName = dbJobEntity.F_JobName; log.F_CreatorTime = now; AlwaysResult result = new AlwaysResult(); if (dbJobEntity.F_JobType == 0) { //反射执行就行 var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory; //反射取指定前后缀的dll var referencedAssemblies = Directory.GetFiles(path, "HT.Cloud.*.dll").Select(Assembly.LoadFrom).ToArray(); var types = referencedAssemblies .SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces() .Contains(typeof(IJobTask)))).ToArray(); string filename = dbJobEntity.F_FileName; var implementType = types.Where(x => x.IsClass && x.FullName == filename).FirstOrDefault(); var obj = System.Activator.CreateInstance(implementType, repository.Tenant); // 创建实例(带参数) MethodInfo method = implementType.GetMethod("Start", new Type[] { }); // 获取方法信息 object[] parameters = null; result = ((Task)method.Invoke(obj, parameters)).GetAwaiter().GetResult(); // 调用方法,参数为空 if (result.state.ToString() == ResultType.success.ToString()) { log.F_EnabledMark = true; log.F_Description = "执行成功," + result.message.ToString(); } else { log.F_EnabledMark = false; log.F_Description = "执行失败," + result.message.ToString(); } } else if (dbJobEntity.F_JobType == 5) { try { repository.ChangeEntityDb(dbJobEntity.F_JobDBProvider).Ado.BeginTran(); if (!string.IsNullOrEmpty(dbJobEntity.F_JobSqlParm)) { var dic = dbJobEntity.F_JobSqlParm.ToObject>(); List list = new List(); foreach (var item in dic) { list.Add(new SugarParameter(item.Key, item.Value)); } var dbResult = await repository.Db.Ado.SqlQueryAsync(dbJobEntity.F_JobSql, list); log.F_EnabledMark = true; log.F_Description = "执行成功," + dbResult.ToJson(); } else { var dbResult = await repository.Db.Ado.SqlQueryAsync(dbJobEntity.F_JobSql); log.F_EnabledMark = true; log.F_Description = "执行成功," + dbResult.ToJson(); } repository.Db.Ado.CommitTran(); } catch (Exception ex) { log.F_EnabledMark = false; log.F_Description = "执行失败," + ex.Message; repository.Db.Ado.RollbackTran(); } } else { HttpMethod method = HttpMethod.Get; switch (dbJobEntity.F_JobType) { case 1: method = HttpMethod.Get; break; case 2: method = HttpMethod.Post; break; case 3: method = HttpMethod.Put; break; case 4: method = HttpMethod.Delete; break; } var dic = dbJobEntity.F_RequestHeaders.ToObject>(); if (dic == null) { dic = new Dictionary(); } //请求头添加租户号 dic.Add("dbNumber", dbJobEntity.F_DbNumber); try { var temp = await _httpClient.ExecuteAsync(dbJobEntity.F_RequestUrl, method, dbJobEntity.F_RequestString, dic); log.F_EnabledMark = true; log.F_Description = $"执行成功。{temp}"; } catch (Exception ex) { log.F_EnabledMark = false; log.F_Description = "执行失败," + ex.Message.ToString(); } } #endregion 执行任务 repository.ChangeEntityDb(GlobalContext.SystemConfig.MainDbNumber); repository.Db.Ado.BeginTran(); //记录执行日志 if (log.F_EnabledMark == true) { await repository.Update(a => a.F_Id == keyValue, a => new OpenJobEntity { F_LastRunMark = true, F_LastRunTime = now }); } else { await repository.Update(a => a.F_Id == keyValue, a => new OpenJobEntity { F_LastRunMark = false, F_LastRunTime = now, F_LastRunErrTime = now, F_LastRunErrMsg = log.F_Description }); } if (dbJobEntity.F_IsLog == "是") { await repository.Db.Insertable(log).ExecuteCommandAsync(); } repository.Db.Ado.CommitTran(); } } catch (Exception ex) { LogHelper.WriteWithTime(ex); if (returnEx) { throw new Exception(ex.Message); } } } public async Task DeleteLogForm(string keyValue) { await repository.Db.Deleteable(a => a.F_JobId == keyValue).ExecuteCommandAsync(); } #endregion 定时任务运行相关操作 } }