| | |
| | | using Newtonsoft.Json; |
| | | using FluentScheduler; |
| | | using Newtonsoft.Json; |
| | | using Rhea.Common; |
| | | using Sundial; |
| | | using System; |
| | | using System.Collections; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | 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 System.Collections.Specialized.BitVector32; |
| | | using static Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser; |
| | | using static Tiger.Model.TrigArgs; |
| | | |
| | | namespace Tiger.Business |
| | | { |
| | | public class InterfaceServiceNew: IInterfaceService |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public class InterfaceServiceNew : IInterfaceService |
| | | { |
| | | #region Sundial计划调度 旧版本使用 |
| | | |
| | | public ISchedulerFactory _schedulerFactory { get; set; } |
| | | public Sundial.ISchedulerFactory _schedulerFactory { get; set; } |
| | | /// <summary> |
| | | /// 设置计划任务工厂类 |
| | | /// </summary> |
| | | /// <param name="schedulerFactory"></param> |
| | | public void SetSchedulerFactory(ISchedulerFactory schedulerFactory) |
| | | public void SetSchedulerFactory(Sundial.ISchedulerFactory schedulerFactory) |
| | | { |
| | | _schedulerFactory = schedulerFactory; |
| | | } |
| | |
| | | /// <typeparam name="TJob"></typeparam> |
| | | /// <param name="newEntity"></param> |
| | | /// <param name="jobParam"></param> |
| | | public ApiAction AddJob<TJob>(TJob newEntity, TskJobParam jobParam) where TJob : class, IJob |
| | | public ApiAction AddJob<TJob>(TJob newEntity, TskJobParam jobParam) where TJob : class, Sundial.IJob |
| | | { |
| | | ApiAction apiAction = new(); |
| | | TriggerBuilder triggerBuilder = Triggers.Period(jobParam.Period*60*1000).LoadFrom(new |
| | | Sundial.TriggerBuilder triggerBuilder = Sundial.Triggers.Period(jobParam.Period * 60 * 1000).LoadFrom(new |
| | | { |
| | | TriggerId = jobParam.JobName + "_trigger1", |
| | | }); |
| | |
| | | /// <typeparam name="TJob"></typeparam> |
| | | /// <param name="jobname"></param> |
| | | /// <param name="triggerBuilders"></param> |
| | | public ApiAction AddJob<TJob>(string jobname, params TriggerBuilder[] triggerBuilders) where TJob : class, IJob |
| | | public ApiAction AddJob<TJob>(string jobname, params Sundial.TriggerBuilder[] triggerBuilders) where TJob : class, Sundial.IJob |
| | | { |
| | | ApiAction apiAction = new(); |
| | | triggerBuilders[0].LoadFrom(new |
| | |
| | | public ApiAction UpdateJob(TSK_JOB job) |
| | | { |
| | | ApiAction apiAction = new ApiAction(); |
| | | IScheduler scheduler = GetJob(job.JobName); |
| | | Sundial.IScheduler scheduler = GetJob(job.JobName); |
| | | var trigger = scheduler.GetTrigger($"{job.JobName}_trigger1"); |
| | | if (trigger.Status == TriggerStatus.Running) |
| | | if (trigger.Status == Sundial.TriggerStatus.Running) |
| | | { |
| | | apiAction.IsSuccessed = false; |
| | | apiAction.Message = $"作业[{job.JobName}]正在运行不能编辑"; |
| | |
| | | public void StartJob(string jobname) |
| | | { |
| | | // 带返回值 |
| | | var scheduleResult = _schedulerFactory.TryRunJob(jobname); |
| | | Sundial.IScheduler scheduler; |
| | | var scheduleResult = _schedulerFactory.TryRunJob(jobname, out scheduler); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | /// </summary> |
| | | /// <param name="jobname"></param> |
| | | /// <returns></returns> |
| | | public IScheduler GetJob(string jobname) |
| | | public Sundial.IScheduler GetJob(string jobname) |
| | | { |
| | | IScheduler scheduler; |
| | | Sundial.IScheduler scheduler; |
| | | var scheduleResult = _schedulerFactory.TryGetJob(jobname, out scheduler); |
| | | return scheduler; |
| | | } |
| | |
| | | /// 获取所有作业 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public List<IScheduler> GetJobs() |
| | | public List<Sundial.IScheduler> GetJobs() |
| | | { |
| | | return _schedulerFactory.GetJobs().ToList(); |
| | | } |
| | |
| | | { |
| | | try |
| | | { |
| | | var jobs = Biz.Db.Queryable<TSK_JOB>().IncludesAllFirstLayer().ToList(); |
| | | foreach (var job in jobs) |
| | | { |
| | | Type type = Type.GetType($"{job.AssemblyName}.{job.JobType},{job.AssemblyName}", throwOnError: true); |
| | | _schedulerFactory.AddJob(type, job.JobName, 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); |
| | | }); |
| | | } |
| | | } |
| | | var jobs = Biz.Db.Queryable<TSK_JOB>().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) |
| | | { |
| | |
| | | } |
| | | return action; |
| | | } |
| | | #endregion |
| | | |
| | | #region 新版本计划调度 FluentScheduler |
| | | /// <summary> |
| | | /// 初始化计划调度 |
| | | /// </summary> |
| | | 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<TSK_TRIG> listTrig = new List<TSK_TRIG>(); |
| | | foreach (var schedule in JobManager.RunningSchedules) |
| | | { |
| | | var job = Biz.Db.Queryable<TSK_JOB>().Where(q => q.JobName == schedule.Name).First(); |
| | | if (job != null) |
| | | { |
| | | TSK_TRIG trig = new TSK_TRIG(); |
| | | trig = Biz.Db.Queryable<TSK_TRIG>().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, $"作业保存到数据库异常"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 添加工作任务 |
| | | /// </summary> |
| | | /// <typeparam name="TJob"></typeparam> |
| | | /// <param name="newEntity"></param> |
| | | /// <param name="jobParam"></param> |
| | | /// <returns></returns> |
| | | public ApiAction AddTskJob<TJob>(TJob newEntity, FluentJobParam jobParam) where TJob : class, ITJob |
| | | { |
| | | ApiAction apiAction = new(); |
| | | try |
| | | { |
| | | if (!JobManager.AllSchedules.Any(q => q.Name == jobParam.JobName)) |
| | | { |
| | | JobManager.AddJob<TJob>((s) => GenerateSchedule(jobParam.Args, s.WithName(jobParam.JobName))); |
| | | string guid = Guid.NewGuid().ToString("N"); |
| | | TSK_JOB job = Biz.Db.Queryable<TSK_JOB>().Where(x => x.JobName == jobParam.JobName).First() ?? new() |
| | | { |
| | | ID = guid, |
| | | Remark = jobParam.Remark, |
| | | JobType = jobParam.JobName, |
| | | AssemblyName = jobParam.AssemblyName, |
| | | JobName = jobParam.JobName, |
| | | }; |
| | | var trigger = Biz.Db.Queryable<TSK_TRIG>().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.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; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 删除作业 |
| | | /// </summary> |
| | | /// <param name="jobname"></param> |
| | | 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<TSK_JOB>().Where(x => x.JobName == jobname).First(); |
| | | var trigger = Biz.Db.Queryable<TSK_TRIG>().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); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 从数据库批量添加任务 |
| | | /// </summary> |
| | | public Registry AddJobsFromDB() |
| | | { |
| | | // 声明一个Registry类 |
| | | var registry = new Registry(); |
| | | try |
| | | { |
| | | var jobs = Biz.Db.Queryable<TSK_JOB>().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<TrigArgs>(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; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 根据实体名注册计划 |
| | | /// </summary> |
| | | /// <typeparam name="TJob"></typeparam> |
| | | /// <param name="entity"></param> |
| | | /// <param name="JobName"></param> |
| | | /// <param name="registry"></param> |
| | | /// <returns></returns> |
| | | private Schedule Schedule<TJob>(TJob entity, string JobName, Registry registry) where TJob : class, ITJob |
| | | { |
| | | return registry.Schedule<TJob>().WithName(typeof(TJob).Name); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 生成计划 |
| | | /// </summary> |
| | | /// <param name="args"></param> |
| | | /// <param name="schedule"></param> |
| | | 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; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 停止服务 |
| | | /// </summary> |
| | | public void Stop() |
| | | { |
| | | JobManager.Stop(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 在任务完成后等待或者停止 |
| | | /// </summary> |
| | | public void StopAndBlock() |
| | | { |
| | | JobManager.StopAndBlock(); |
| | | } |
| | | |
| | | #endregion |
| | | } |
| | | } |