using System; using System.ComponentModel; using System.Xml; using System.Data; using System.Reflection; using System.Configuration; using Autofac; using Bowin.Common.Log; using EMIS.CommonLogic.SystemServices; using EMIS.Entities; namespace EMIS.Services { #region 所有的服务工作接口 IServiceJob /// /// IServiceJob : 所有的服务工作接口 /// public interface IServiceJob { string JobID { get; set; } string JobName { get; set; } Guid SchedulerID { get; set; } int MaxThreadSize { get; set; } bool IsDebug { get; set; } string CertFile { get; set; } void ExecuteJob(); DateTime AllTimeBegin { get; set; } DateTime AllTimeEnd { get; set; } int AllUseSeconds { get; set; } string Desc { get; set; } } #endregion #region 所有Job的基类 /// /// 所有Job的基类。 /// public abstract class EAPServiceJob : IServiceJob { #region 实现IServiceJob接口 private string _jobid = ""; private string _jobname = ""; private Guid _schedulerid = Guid.Empty; private int _MaxThreadSize = 1; private bool _isdubug = false; private string _certfile = ""; DateTime _AllTimeBegin; DateTime _AllTimeEnd; int _AllUseSeconds; DateTime _OneScheduleTimeBegin; DateTime _OneScheduleTimeEnd; int _OneScheduleUseSeconds; bool _Successful; string _Desc; /// /// 任务ID /// public string JobID { get { return _jobid; } set { _jobid = value; } } /// /// 任务名称 /// public string JobName { get { return _jobname; } set { _jobname = value; } } /// /// 执行ID /// public Guid SchedulerID { get { return _schedulerid; } set { _schedulerid = value; } } /// /// 子服务同时最大线程数 /// public int MaxThreadSize { get { return _MaxThreadSize; } set { _MaxThreadSize = value; } } /// /// 是否调试状态 /// public bool IsDebug { get { return _isdubug; } set { _isdubug = value; } } /// /// 证书文件 /// public string CertFile { get { return this._certfile; } set { this._certfile = value; } } /// /// 总体执行开始时间 /// public DateTime AllTimeBegin { get { return _AllTimeBegin; } set { _AllTimeBegin = value; } } /// /// 总体执行结束时间 /// public DateTime AllTimeEnd { get { return _AllTimeEnd; } set { _AllTimeEnd = value; } } /// /// 总体服务执行耗时秒数 /// public int AllUseSeconds { get { return _AllUseSeconds; } set { _AllUseSeconds = value; } } /// /// 单个服务执行开始时间 /// public DateTime OneScheduleTimeBegin { get { return _OneScheduleTimeBegin; } set { _OneScheduleTimeBegin = value; } } /// /// 单个服务执行结束时间 /// public DateTime OneScheduleTimeEnd { get { return _OneScheduleTimeEnd; } set { _OneScheduleTimeEnd = value; } } /// /// 单个服务执行耗时秒数 /// public int OneScheduleUseSeconds { get { return _OneScheduleUseSeconds; } set { _OneScheduleUseSeconds = value; } } /// /// 是否执行成功 /// public bool Successful { get { return _Successful; } set { _Successful = value; } } /// /// 执行结果备注信息 /// public string Desc { get { return _Desc; } set { _Desc = value; } } #endregion #region 运行JOB public void RunJobOnce() { this.MyJob(); } #endregion public virtual void ExecuteJob() { //起止配对;容易找起止。 Guid tagID = Guid.NewGuid(); try { this.Init(); Desc = "服务【" + this._jobname + "】开始执行:{" + tagID.ToString() + "}"; LogHelper.WriteLog(LogType.ServiceLog, Desc); //先置最后执行时间;防止多线程一次集中连续执行。 using (var scop = Program.AutofacContainer.BeginLifetimeScope()) { var ScheduleServices = scop.Resolve(); ScheduleServices.UpdateLastRun(SchedulerID); } this.MyJob(); OneScheduleTimeEnd = System.DateTime.Now; TimeSpan ts = new TimeSpan(); ts = OneScheduleTimeEnd - OneScheduleTimeBegin; OneScheduleUseSeconds = Convert.ToInt32(ts.TotalSeconds); Desc = "服务【" + this._jobname + "】结束执行;耗时:" + OneScheduleUseSeconds.ToString() + "秒。{" + tagID.ToString() + "}"; LogHelper.WriteLog(LogType.ServiceLog, Desc); Successful = true; UpdateSchedulingLog(SchedulerID, JobID, OneScheduleTimeBegin, OneScheduleTimeEnd, OneScheduleUseSeconds, Successful, "执行成功"); } catch (Exception err) { OneScheduleTimeEnd = System.DateTime.Now; Desc = "服务【" + this._jobname + "】执行异常:" + err.Message; TimeSpan ts = new TimeSpan(); ts = OneScheduleTimeEnd - OneScheduleTimeBegin; OneScheduleUseSeconds = Convert.ToInt32(ts.TotalSeconds); //转换时间间隔为 秒 LogHelper.WriteLog(LogType.ServiceLog, "服务【" + this._jobname + "】结束;耗时:" + OneScheduleUseSeconds.ToString() + "秒;{" + tagID.ToString() + "} \r\n 执行结果:\r\n " + Desc); Successful = true; UpdateSchedulingLog(SchedulerID, JobID, OneScheduleTimeBegin, OneScheduleTimeEnd, OneScheduleUseSeconds, Successful, "执行失败:" + err.Message); } finally { } } protected virtual bool Init() { Successful = true; AllTimeBegin = System.DateTime.Now; AllTimeEnd = System.DateTime.Now; AllUseSeconds = 0; OneScheduleTimeBegin = System.DateTime.Now; OneScheduleTimeEnd = System.DateTime.Now; OneScheduleUseSeconds = 0; Desc = "服务【" + this._jobname + "】开始执行:"; return true; } protected abstract bool MyJob(); #region 修改具体服务调度表中的执行信息,记录服务调度历史记录。 /// /// 修改具体服务调度表中的执行信息,记录服务调度历史记录。 /// public void UpdateSchedulingLog(Guid schedulerID, string jobID, DateTime scheduleTimeBegin, DateTime scheduleTimeEnd, int UseSeconds, bool successful, string desc) { try { using (var scop = Program.AutofacContainer.BeginLifetimeScope()) { var ScheduleServices = scop.Resolve(); ScheduleServices.UpdateLastRunAndLoopNum(SchedulerID); Sys_ScheduleLog log = new Sys_ScheduleLog(); log.scid = schedulerID; log.timeBegin = scheduleTimeBegin; log.timeEnd = scheduleTimeEnd; log.successful = successful; log.useSeconds = UseSeconds; log.Desc = desc; ScheduleServices.InsertLog(log); } } catch (Exception ce) { LogHelper.WriteLog(LogType.ServiceLog, "操作数据库异常:" + ce.Message); } } #endregion } #endregion #region ServiceWrapper的接口 namespace MyEAPServiceWrapper { /// /// ServiceWrapper的接口。 /// 开启多线程,并且控制每个子服务当前最多只有一个线程在执行;多个子服务可以同时执行;防止不同的子服务彼此相互堵塞。 /// public interface IServiceWrapper { bool IsDebug { get; set; } bool Execute(); } } #endregion #region EAPServiceWrapper namespace MyEAPServiceWrapper { /// /// ServiceWrapper的具体子服务执行。 /// 开启多线程,并且控制每个子服务当前最多只有一个线程在执行;多个子服务可以同时执行;防止不同的子服务彼此相互堵塞。 /// using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Linq.Expressions; using System.Data.Entity; using System.Data.SqlClient; using System.Data; using System.Collections; public class ServiceWrapper : IServiceWrapper { #region 实现IServiceWrapper接口属性 private bool _isdubug = false; DateTime _AllTimeBegin; DateTime _AllTimeEnd; int _AllUseSeconds; DateTime _OneScheduleTimeBegin; DateTime _OneScheduleTimeEnd; int _OneScheduleUseSeconds; bool _Successful; string _Desc; Guid SchedulerID = Guid.Empty; int MaxThreadSize = 1; string JobID = ""; string JobName = ""; string AssemName = ""; string ClassName = ""; /// /// 是否调试状态 /// public bool IsDebug { get { return _isdubug; } set { _isdubug = value; } } /// /// 总体执行开始时间 /// public DateTime AllTimeBegin { get { return _AllTimeBegin; } set { _AllTimeBegin = value; } } /// /// 总体执行结束时间 /// public DateTime AllTimeEnd { get { return _AllTimeEnd; } set { _AllTimeEnd = value; } } /// /// 总体服务执行耗时秒数 /// public int AllUseSeconds { get { return _AllUseSeconds; } set { _AllUseSeconds = value; } } /// /// 单个服务执行开始时间 /// public DateTime OneScheduleTimeBegin { get { return _OneScheduleTimeBegin; } set { _OneScheduleTimeBegin = value; } } /// /// 单个服务执行结束时间 /// public DateTime OneScheduleTimeEnd { get { return _OneScheduleTimeEnd; } set { _OneScheduleTimeEnd = value; } } /// /// 单个服务执行耗时秒数 /// public int OneScheduleUseSeconds { get { return _OneScheduleUseSeconds; } set { _OneScheduleUseSeconds = value; } } /// /// 是否执行成功 /// public bool Successful { get { return _Successful; } set { _Successful = value; } } /// /// 执行结果备注信息 /// public string Desc { get { return _Desc; } set { _Desc = value; } } #endregion #region 子服务线程控制 public class ThreadInfo { public int ManagedThreadId { get; set; } public string Name { get; set; } public bool IsAlive { get; set; } public DateTime StartTime { get; set; } } /// /// 存放当前正在执行的子服务线程信息 /// static System.Collections.Generic.List NowExecThreadsInfo = new System.Collections.Generic.List(); #endregion #region 整体控制执行服务 /// /// 开启多线程,并且控制每个子服务当前最多只有一个线程在执行;多个子服务可以同时执行;防止不同的子服务彼此相互堵塞。 /// /// public bool Execute() { //AllTimeEnd = System.DateTime.Now; //Desc = "总体服务执行成功!"; //TimeSpan ts = new TimeSpan(); //ts = AllTimeEnd - AllTimeBegin; //AllUseSeconds = Convert.ToInt32(ts.TotalSeconds); //转换时间间隔为 秒 //Log.WriteLog("总体服务结束;耗时:" + AllUseSeconds.ToString() + "秒; \r\n 执行结果:\r\n " + Desc); bool bResult = true; //string serverName = ConfigurationManager.AppSettings["ServerName"]; var scheduleJobList = QureyScheduleJobs(); foreach (var scheduleJob in scheduleJobList) { string sStartDate = scheduleJob.datebegin.ToString().Trim(); ;//20040707 sStartDate = sStartDate.Substring(0, 4) + "-" + sStartDate.Substring(4, 2) + "-" + sStartDate.Substring(6, 2); //转换成2004-07-07 DateTime tmpStartDate = System.Convert.ToDateTime(sStartDate); sStartDate = scheduleJob.dateend.ToString().Trim(); sStartDate = sStartDate.Substring(0, 4) + "-" + sStartDate.Substring(4, 2) + "-" + sStartDate.Substring(6, 2); //转换成2004-07-07 DateTime tmpEndDate = System.Convert.ToDateTime(sStartDate); int scinterval = scheduleJob.scinterval; /* D:天 H:小时 M:分钟 S:秒 */ switch (scheduleJob.scmode.ToUpper()) { case "D": scinterval = scheduleJob.scinterval * (60 * 60 * 24); //对于周期跨天的,要防止累计偏差而出现跳天现象(空出2分钟的柔韧空间值)。 scinterval = scinterval - 120; break; case "H": scinterval = scheduleJob.scinterval * (60 * 60); break; case "M": scinterval = scheduleJob.scinterval * (60); break; //默认秒 default: break; } this.SchedulerID = scheduleJob.scid; this.MaxThreadSize = 1; this.JobID = scheduleJob.Sys_ScheduleJob.jobid; this.JobName = scheduleJob.Sys_ScheduleJob.jobname; this.AssemName = scheduleJob.Sys_ScheduleJob.assemname; this.ClassName = scheduleJob.Sys_ScheduleJob.classname; //检查该项服务是否到了下次运行时间,如是则运行。 if (this.CheckJobAllowRun(tmpStartDate, tmpEndDate, scinterval, scheduleJob.lastrun, scheduleJob.timefrom, scheduleJob.timeto)) { //this.JobRun(tmpSchedulerID, tmpJobID,tmpServerName, tmpJobName, tmpAssemName, tmpClassName); System.Threading.Thread thread = new System.Threading.Thread(JobRun); thread.Start(); //防止循环后再次获取数据库进行判断,而当前的验证还没有加入线程属性导致可能多1个子线程服务在运行;需要停顿一下。 System.Threading.Thread.Sleep(3000); } } return bResult; } #endregion #region 检查是允许运行 /// /// 检查任务是否允许运行 /// /// /// /// /// /// private bool CheckJobAllowRun(DateTime StartDate, DateTime EndDate, int SecondTiple, DateTime? LastUpdate, string StartTime, string EndTime) { DateTime nowday = new System.DateTime(System.DateTime.Now.Year, System.DateTime.Now.Month, System.DateTime.Now.Day); StartDate = new DateTime(StartDate.Year, StartDate.Month, StartDate.Day); EndDate = new DateTime(EndDate.Year, EndDate.Month, EndDate.Day); if ((nowday >= StartDate) && (nowday <= EndDate)) { if (InRunTimeRange(StartTime, EndTime)) { if ((ReturnSecondFromDate(System.DateTime.Now) - ReturnSecondFromDate(LastUpdate)) >= SecondTiple) return true; else return false; } else return false; } else { return false; } } /// /// 把日期转化为秒 /// /// /// private long ReturnSecondFromDate(DateTime? datetime1) { if (!datetime1.HasValue) return 0; return (long)((datetime1.Value.Year * 365 + datetime1.Value.DayOfYear) * 24 * 60 + datetime1.Value.Hour * 60 + datetime1.Value.Minute) * 60 + datetime1.Value.Second; } private bool InRunTimeRange(string StartTime, string EndTime) { int mHour = System.DateTime.Now.Hour; int mMinute = System.DateTime.Now.Minute; int mSecond = System.DateTime.Now.Second; string[] splStartTime = StartTime.Split(':'); int mStartHour = Convert.ToInt32(splStartTime[0]); int mStartMinute = Convert.ToInt32(splStartTime[1]); int mStartSecond = Convert.ToInt32(splStartTime[2]); string[] splEndTime = EndTime.Split(':'); int mEndHour = Convert.ToInt32(splEndTime[0]); int mEndMinute = Convert.ToInt32(splEndTime[1]); int mEndSecond = Convert.ToInt32(splEndTime[2]); int mCurrent = mHour * 60 * 60 + mMinute * 60 + mSecond; int mStart = mStartHour * 60 * 60 + mStartMinute * 60 + mStartSecond; int mEnd = mEndHour * 60 * 60 + mEndMinute * 60 + mEndSecond; if (mCurrent >= mStart && mCurrent <= mEnd) return true; return false; } #endregion #region 运行具体某个Job /// /// 运行服务工作,不返回错误以免将其他的工作也停止 /// private void JobRun(string schedulerID, string jobID,string serverName, string jobName, string assemName, string className) /// /// /// /// private void JobRun() { Guid schedulerID = SchedulerID; int maxThreadSize = MaxThreadSize; string jobID = JobID; string jobName = JobName; string assemName = AssemName; string className = ClassName; bool thisTimeNeedDo = true; ThreadInfo threadInfo = new ThreadInfo(); try { //判断检查该项服务对应的线程是否在运行。 System.Threading.Thread currentSubServiceThread = System.Threading.Thread.CurrentThread; currentSubServiceThread.Name = className; //启动时间在6个钟内的线程才有效 var currentSubServices = (from a in NowExecThreadsInfo where a.Name == className && a.StartTime > DateTime.Now.AddHours(-6) select new ThreadInfo { ManagedThreadId = a.ManagedThreadId, Name = a.Name, IsAlive = a.IsAlive, StartTime = a.StartTime } ).ToList(); int currentSubServiceNum = currentSubServices.Count; LogHelper.WriteLog(LogType.ServiceLog, "当前【" + className + "】有个(" + currentSubServiceNum.ToString() + ")线程在执行。最大线程数:" + maxThreadSize.ToString() + ";时间:" + DateTime.Now.ToString()); if (currentSubServiceNum >= maxThreadSize) { thisTimeNeedDo = false; LogHelper.WriteLog(LogType.ServiceLog, "当前【" + className + "】正已经有个(" + currentSubServiceNum.ToString() + ")线程在执行,本次跳过激发执行。" + DateTime.Now.ToString()); } if (thisTimeNeedDo) { //加线程子服务信息 threadInfo.ManagedThreadId = currentSubServiceThread.ManagedThreadId; threadInfo.Name = currentSubServiceThread.Name; threadInfo.IsAlive = currentSubServiceThread.IsAlive; threadInfo.StartTime = DateTime.Now; NowExecThreadsInfo.Add(threadInfo); string fullClassName = ""; Assembly assem = Assembly.Load(assemName); if (className.IndexOf(".") > 0) { fullClassName = className; } else { fullClassName = assemName + "." + className; } //Log.WriteLog("TestHere01 " + fullClassName); Type classType = assem.GetType(fullClassName); IServiceJob fss = (IServiceJob)System.Activator.CreateInstance(classType); fss.SchedulerID = schedulerID; fss.JobID = jobID; fss.JobName = jobName; fss.IsDebug = this._isdubug; fss.CertFile = ConfigurationManager.AppSettings["CertFile"]; fss.ExecuteJob(); //运行Job } } catch (Exception ce) { LogHelper.WriteLog(LogType.ServiceLog, "服务【" + jobName + "】执行异常:" + ce.Message); } finally { if (thisTimeNeedDo) { //处理完毕后清除线程子服务信息 NowExecThreadsInfo.Remove(threadInfo); } } } #endregion #region 获取总体服务信息;然后处理那些需要执行的各个具体服务。 /// /// 获取总体服务信息;然后处理那些需要执行的各个具体服务。 /// public List QureyScheduleJobs() { try { using (var scop = Program.AutofacContainer.BeginLifetimeScope()) { var ScheduleServices = scop.Resolve(); return ScheduleServices.GetJobList(); } } catch (Exception ce) { LogHelper.WriteLog(LogType.ServiceLog, "操作数据库异常:" + ce.Message); } finally { } return new List(); } #endregion } #endregion } }