using FluentScheduler; using Newtonsoft.Json; using Rhea.Common; using Sundial; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; using Tiger.IBusiness; using Tiger.Model; using Tiger.Model.Entitys.MES.Position; using Tiger.Model.Minsun; using static Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser; using static Tiger.Model.TrigArgs; namespace Tiger.Business { /// /// /// public class InterfaceServiceNew : IInterfaceService { #region Sundial计划调度 旧版本使用 public Sundial.ISchedulerFactory _schedulerFactory { get; set; } /// /// 设置计划任务工厂类 /// /// public void SetSchedulerFactory(Sundial.ISchedulerFactory schedulerFactory) { _schedulerFactory = schedulerFactory; } /// /// 根据实体类名及作业名称添加作业 /// /// /// /// public ApiAction AddJob(TJob newEntity, TskJobParam jobParam) where TJob : class, Sundial.IJob { ApiAction apiAction = new(); Sundial.TriggerBuilder triggerBuilder = Sundial.Triggers.Period(jobParam.Period * 60 * 1000).LoadFrom(new { TriggerId = jobParam.JobName + "_trigger1", }); _schedulerFactory.AddJob(jobParam.JobName, triggerBuilder); var trigger = GetJob(jobParam.JobName).GetTrigger($"{jobParam.JobName}_trigger1"); TSK_JOB entity = ReturnDetail(jobParam.JobName); entity.Remark = jobParam.Remark; entity.JobType = typeof(TJob).Name; entity.JobName = jobParam.JobName; entity.TriggersWithGhost = new List { JsonConvert.DeserializeObject(JsonConvert.SerializeObject(trigger)) }; entity.Triggers[0].Args = jobParam.Period.ToString(); apiAction = SaveJob(entity); apiAction.Data = entity; return apiAction; } /// /// 根据作业名称添加作业 /// /// /// /// public ApiAction AddJob(string jobname, params Sundial.TriggerBuilder[] triggerBuilders) where TJob : class, Sundial.IJob { ApiAction apiAction = new(); triggerBuilders[0].LoadFrom(new { TriggerId = jobname + "_trigger1", }); _schedulerFactory.AddJob(jobname, triggerBuilders); var trigger = GetJob(jobname).GetTrigger($"{jobname}_trigger1"); TSK_JOB entity = ReturnDetail(jobname); entity.TriggersWithGhost = new List { JsonConvert.DeserializeObject(JsonConvert.SerializeObject(trigger)) }; apiAction = SaveJob(entity); apiAction.Data = entity; return apiAction; } /// /// 更新作业 /// /// /// public ApiAction UpdateJob(TSK_JOB job) { ApiAction apiAction = new ApiAction(); Sundial.IScheduler scheduler = GetJob(job.JobName); var trigger = scheduler.GetTrigger($"{job.JobName}_trigger1"); if (trigger.Status == Sundial.TriggerStatus.Running) { apiAction.IsSuccessed = false; apiAction.Message = $"作业[{job.JobName}]正在运行不能编辑"; } var triggerEntity = Biz.Db.Queryable().Where(x => x.JobId == job.ID).First(); if (triggerEntity != null) { triggerEntity.Status = (int)trigger.Status; triggerEntity.Args = job.uPeriod.ToString(); } var db = Business.Biz.Db; //保存到数据库 var dbTran = db.UseTran(() => { if (job != null) { db.Updateable(job, "system").ExecuteCommand(); } if (triggerEntity != null) { db.Updateable(triggerEntity, "system").ExecuteCommand(); } }); if (!dbTran.IsSuccess) { apiAction.GetResponse().CatchExceptionWithLog(dbTran.ErrorException, $"作业保存到数据库异常"); } //更新触发器周期 scheduler.UpdateTrigger($"{job.JobName}_trigger1", triggerBuilder => { triggerBuilder.SetArgs(job.uPeriod * 60 * 1000); }); ; return apiAction; } private TSK_JOB ReturnDetail(string jobname) { var jobDetail = GetJob(jobname).GetJobDetail(); return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(jobDetail)); } /// /// 启动所有作业 /// public void StartAllJob() { _schedulerFactory.StartAll(); } /// /// 启动单个作业 /// /// public void StartJob(string jobname) { // 带返回值 Sundial.IScheduler scheduler; var scheduleResult = _schedulerFactory.TryRunJob(jobname, out scheduler); } /// /// 获取单个作业 /// /// /// public Sundial.IScheduler GetJob(string jobname) { Sundial.IScheduler scheduler; var scheduleResult = _schedulerFactory.TryGetJob(jobname, out scheduler); return scheduler; } /// /// 获取所有作业 /// /// public List GetJobs() { return _schedulerFactory.GetJobs().ToList(); } /// /// 暂停作业 /// /// public void PauseJob(string jobname) { var scheduler = GetJob(jobname); if (scheduler != null) { scheduler.Pause(); } } /// /// 删除作业 /// /// public void RemoveJob(string jobname) { var scheduler = GetJob(jobname); if (scheduler != null) { scheduler.Remove(); } } /// /// 从数据库加载作业 /// public void AddJobFromDB() { try { var jobs = Biz.Db.Queryable().IncludesAllFirstLayer().ToList(); foreach (var job in jobs) { Type type = Type.GetType($"{job.AssemblyName}.{job.JobType},{job.AssemblyName}", throwOnError: true); _schedulerFactory.AddJob(type, job.JobName, Sundial.Triggers.Period(Convert.ToInt32(job.Triggers?[0].Args ?? "3") * 60 * 1000)); if (job.Triggers[0]?.Status == 3) { Work.DoAsync(() => { Thread.Sleep(2000); PauseJob(job.JobName); }); } } } catch (System.Exception ex) { Logger.Console.Fatal(ex, "Add Job From DB Exception"); } } /// /// 作业保存到数据库 /// /// private ApiAction SaveJob(TSK_JOB entity) { var action = new ApiAction(); entity.ID = Guid.NewGuid().ToString("N"); entity.Triggers[0].JobId = entity.ID; if (Biz.Db.Queryable().Where(x => x.JobName == entity.JobName && x.JobType == entity.JobType && x.AssemblyName == entity.AssemblyName).Any()) { action.IsSuccessed = false; action.Message = $"作业已经存在,不能保存数据"; return action; } var db = Business.Biz.Db; //保存到数据库 var dbTran = db.UseTran(() => { if (entity != null) { db.Insertable(entity, "system").ExecuteCommand(); } if (entity.Triggers.Any()) { db.Insertable(entity.Triggers, "system").ExecuteCommand(); } }); if (!dbTran.IsSuccess) { action.GetResponse().CatchExceptionWithLog(dbTran.ErrorException, $"作业保存到数据库异常"); } return action; } #endregion #region 新版本计划调度 FluentScheduler /// /// 初始化计划调度 /// public void JobInitialize() { JobManager.Initialize(AddJobsFromDB()); JobManager.JobException += info => Logger.Scheduler.Error("An error just happened with a scheduled job: " + info.Exception); JobManager.JobStart += info => Logger.Scheduler.Info($"{info.Name}: started\r\n"); JobManager.JobEnd += info => Logger.Scheduler.Info($"{info.Name}: ended ({info.Duration})\r\n"); SaveRunningStatus(); //保存状态 } private void SaveRunningStatus() { List listTrig = new List(); foreach (var schedule in JobManager.RunningSchedules) { var job = Biz.Db.Queryable().Where(q => q.JobName == schedule.Name).First(); if (job != null) { TSK_TRIG trig = new TSK_TRIG(); trig = Biz.Db.Queryable().Where(q => q.JobId == job.ID).First(); trig.Status = TSK_TRIG.Statuss.Running.GetValue(); trig.StartTime = DateTime.Now; listTrig.Add(trig); } } var db = Biz.Db; //保存到数据库 var dbTran = db.UseTran(() => { if (listTrig.Count > 0) { db.Updateable(listTrig, "system").UpdateColumns(q => new { q.Status, q.UPDATE_USER, q.UPDATE_TIME }).ExecuteCommand(); } }); if (!dbTran.IsSuccess) { Logger.Scheduler.Trace(dbTran.ErrorException, $"作业保存到数据库异常"); } } /// /// 添加工作任务 /// /// /// /// /// public ApiAction AddTskJob(TJob newEntity, FluentJobParam jobParam) where TJob : class, ITJob { ApiAction apiAction = new(); try { if (!JobManager.AllSchedules.Any(q => q.Name == jobParam.JobName)) { JobManager.AddJob((s) => GenerateSchedule(jobParam.Args, s.WithName(jobParam.JobName))); string guid = Guid.NewGuid().ToString("N"); if (Biz.Db.Queryable().Any(x => (x.JobName != jobParam.JobName && x.JobType == jobParam.DataType) || (x.JobName == jobParam.JobName && x.JobType != jobParam.DataType))) { apiAction.IsSuccessed = false; apiAction.LocaleMsg = new($"相同的类名不能有不同的任务名或者相同的任务名不能有不同的类名"); return apiAction; } TSK_JOB job = Biz.Db.Queryable().Where(x => x.JobName == jobParam.JobName && x.JobType == jobParam.DataType).First() ?? new() { ID = guid, }; job.Remark = jobParam.Remark; job.JobType = jobParam.DataType; job.AssemblyName = jobParam.AssemblyName; job.JobName = jobParam.JobName; var trigger = Biz.Db.Queryable().Where(x => x.JobId == job.ID).First() ?? new TSK_TRIG() { JobId = guid, StartTime = DateTime.Now, NumberOfRuns = 1, }; trigger.Args = JsonConvert.SerializeObject(jobParam.Args); trigger.Status = TSK_TRIG.Statuss.Running.GetValue(); var db = Biz.Db; //保存到数据库 var dbTran = db.UseTran(() => { var y = db.Storageable(job) .WhereColumns(t => new { t.JobName,t.JobType, t.GHOST_ROW }) .ToStorage(); y.AsInsertable.ExecuteCommand(); y.AsUpdateable.IgnoreColumns(x => x.ID).ExecuteCommand(); var z = db.Storageable(trigger) .WhereColumns(t => new { t.JobId, t.GHOST_ROW }) .ToStorage(); z.AsInsertable.ExecuteCommand(); z.AsUpdateable.IgnoreColumns(x => x.ID).ExecuteCommand(); }); if (!dbTran.IsSuccess) { apiAction.CatchExceptionWithLog(dbTran.ErrorException, $"添加工作任务时保存到数据库异常"); } } } catch (System.Exception ex) { apiAction.CatchExceptionWithLog(ex); } if (!apiAction.IsSuccessed) { JobManager.RemoveJob(jobParam.JobName); } return apiAction; } /// /// 删除作业 /// /// public void RemovefJob(string jobname) { if (JobManager.AllSchedules.Any(q => q.Name == jobname)) { string guid = Guid.NewGuid().ToString("N"); TSK_JOB job = Biz.Db.Queryable().Where(x => x.JobName == jobname).First(); var trigger = Biz.Db.Queryable().Where(x => x.JobId == job.ID).First(); trigger.Status = TSK_TRIG.Statuss.Stop.GetValue(); var db = Biz.Db; //保存到数据库 var dbTran = db.UseTran(() => { db.Updateable(trigger, "system_job").UpdateColumns(q=>new { q.Status,q.UPDATE_TIME,q.UPDATE_USER}).ExecuteCommand(); }); if (!dbTran.IsSuccess) { Logger.Scheduler.Fatal(dbTran.ErrorException, $"添加工作任务时保存到数据库异常"); } } JobManager.RemoveJob(jobname); } /// /// 从数据库批量添加任务 /// public Registry AddJobsFromDB() { // 声明一个Registry类 var registry = new Registry(); try { var jobs = Biz.Db.Queryable().IncludesAllFirstLayer().ToList(); foreach (var job in jobs) { //if (job.JobName == "fU9C_MES_GetWo" || job.JobName == "fTest") { Type type = Type.GetType($"{job.AssemblyName}.{job.JobType},{job.AssemblyName}", throwOnError: true); dynamic _type = Activator.CreateInstance(type); TrigArgs args = JsonConvert.DeserializeObject(job.Triggers[0].Args); Schedule schedule = Schedule(_type, job.JobName, registry); //生成计划 GenerateSchedule(args, schedule); } } } catch (System.Exception ex) { Logger.Console.Fatal(ex, "Add Job From DB Exception"); } return registry; } /// /// 根据实体名注册计划 /// /// /// /// /// /// private Schedule Schedule(TJob entity, string JobName, Registry registry) where TJob : class, ITJob { return registry.Schedule().WithName(JobName); } /// /// 生成计划 /// /// /// private void GenerateSchedule(TrigArgs args, Schedule schedule) { SpecificTimeUnit specificTimeUnit = null; TimeUnit timeUnit = null; if (args.NonReentrant == "Y") { schedule = schedule.NonReentrant(); } //就是是否跟之前的还没运行完的计划同时运行。 switch (args.runType) { case RunType.ToRunNow: specificTimeUnit = schedule.ToRunNow(); //马上运行 break; case RunType.ToRunOnceAt: specificTimeUnit = schedule.ToRunOnceAt(args.ToRunOnceAtDt.AddMinutes(args.NowAddMinutes)); //运行一次在哪个时间, break; case RunType.ToRunOnceIn: timeUnit = schedule.ToRunOnceIn(args.ToRunOnceIn); //在多少后运行一次 break; case RunType.ToRunEvery: timeUnit = schedule.ToRunEvery(args.ToRunEvery); //每隔多少运行一回 break; } if (specificTimeUnit != null) { timeUnit = specificTimeUnit.AndEvery(args.ToRunEvery); } //每隔多少运行一回,加在ToRunNow、ToRunOnceAt后面 //按时间类型来运行 switch (args.Type) { case TrigArgs.EveryType.Milliseconds: timeUnit.Milliseconds(); break; case TrigArgs.EveryType.Seconds: timeUnit.Seconds(); //表示按秒,多少秒要看前面Every的数,比如:ToRunEvery(5).Seconds() 这个就表示 隔5秒运行一次 break; case TrigArgs.EveryType.Minutes: timeUnit.Minutes(); break; case TrigArgs.EveryType.Hours: if (args.Minutes > 0) { timeUnit.Hours().At(args.Minutes); //表示按每小时的分钟,多少分要看前面Every的数,比如:ToRunEvery(1).Hours().At(5) 这个就表示 隔1小时的第5分钟运行一次 } else { timeUnit.Hours(); } break; case TrigArgs.EveryType.Days: if (args.Hours > 0) { timeUnit.Days().At(args.Hours, args.Minutes); //表示按天,多少天要看前面Every的数,比如:ToRunEvery(2).Days().At(14, 15) 这个就表示 隔2天的14:15运行一次 } else { timeUnit.Days(); } break; case TrigArgs.EveryType.Weeks: if (args.Hours > 0) { timeUnit.Weeks().At(args.Hours, args.Minutes); //表示按周,多少周要看前面Every的数,比如:ToRunEvery(1).Weeks().At(14, 15) 这个就表示 隔1周的14:15运行一次 } else { timeUnit.Weeks(); } break; case TrigArgs.EveryType.Weekdays: if (args.Hours > 0) { timeUnit.Weekdays().At(args.Hours, args.Minutes); } else { timeUnit.Weekdays(); } break; case TrigArgs.EveryType.Months: if (args.Days > 0 && args.Hours > 0) { timeUnit.Months().On(args.Days).At(args.Hours, args.Minutes); } else { timeUnit.Months(); } break; } } /// /// 立即运行 /// /// public ApiAction ImmediateRun(TJob newEntity, string jobname) where TJob : class, ITJob { ApiAction apiAction = new(); try { if (JobManager.AllSchedules.Any(q => q.Name == jobname)) { JobManager.RemoveJob(jobname); string guid = Guid.NewGuid().ToString("N"); TSK_JOB job = Biz.Db.Queryable().Where(x => x.JobName == jobname).First(); var trigger = Biz.Db.Queryable().Where(x => x.JobId == job.ID).First(); TrigArgs args = JsonConvert.DeserializeObject(job.Triggers[0].Args); args.runType = RunType.ToRunNow; JobManager.AddJob((s) => GenerateSchedule(args, s.WithName(jobname))); trigger.Status = TSK_TRIG.Statuss.Running.GetValue(); trigger.Args = JsonConvert.SerializeObject(args); var db = Biz.Db; //保存到数据库 var dbTran = db.UseTran(() => { db.Updateable(trigger, "system_ImmediateRun_job").UpdateColumns(q => new { q.Status, q.Args, q.UPDATE_TIME, q.UPDATE_USER }).ExecuteCommand(); }); if (!dbTran.IsSuccess) { Logger.Scheduler.Fatal(dbTran.ErrorException, $"立即运行工作任务时保存状态到数据库异常"); } apiAction.LocaleMsg = new($"立即运行工作任务成功"); } } catch (System.Exception ex) { apiAction.CatchExceptionWithLog(ex); } return apiAction; } /// /// 停止服务 /// public void Stop() { JobManager.Stop(); } /// /// 在任务完成后等待或者停止 /// public void StopAndBlock() { JobManager.StopAndBlock(); } #endregion } }