服务端的TigerApi 框架,基于.NET6 2024 版本
Ben Lin
2024-10-28 20a0c7b19c248617fb1852a63834bb668831f86e
Tiger.Business/Services/Base/InterfaceServiceNew.cs
@@ -1,29 +1,38 @@
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.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 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;
        }
@@ -34,10 +43,10 @@
        /// <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",
            });
@@ -60,7 +69,7 @@
        /// <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
@@ -84,9 +93,9 @@
        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}]正在运行不能编辑";
@@ -143,7 +152,7 @@
        public void StartJob(string jobname)
        {
            // 带返回值
            IScheduler scheduler;
            Sundial.IScheduler scheduler;
            var scheduleResult = _schedulerFactory.TryRunJob(jobname, out scheduler);
        }
@@ -152,9 +161,9 @@
        /// </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;
        }
@@ -163,7 +172,7 @@
        /// 获取所有作业
        /// </summary>
        /// <returns></returns>
        public List<IScheduler> GetJobs()
        public List<Sundial.IScheduler> GetJobs()
        {
            return _schedulerFactory.GetJobs().ToList();
        }
@@ -200,20 +209,20 @@
        {
            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)
            {
@@ -255,5 +264,298 @@
            }
            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");
                    if (Biz.Db.Queryable<TSK_JOB>().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<TSK_JOB>().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<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.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;
        }
        /// <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(JobName);
        }
        /// <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
    }
}