using System; using System.Data; using System.Diagnostics; using System.IO; using System.Runtime.CompilerServices; using System.ServiceProcess; using System.Xml; using Microsoft.VisualBasic; using Microsoft.VisualBasic.CompilerServices; namespace AutoLoaderService_Base { public class Service1 : ServiceBase { // //建立AutoLoaderJob所使用的DataTable private DataTable dtAutoLoaderJob; // //Trace & Log private bool blnLogFile = false; private bool blnTraceFile = false; private string strLogFilePath = string.Empty; private string strTraceFilePath = string.Empty; // //取出Job檔案路徑 private string strJobFilePath = ""; // 取回JOB LIST 到 JOB QUEUE的時間間隔(單位:分鐘) '20211015 13871,修正為*1000是秒, *60才是分鐘 private int MonitorjoblistDuration = (int)Math.Round(Conversions.ToDouble(modWIN.GetAppSettings("MonitorjoblistDuration")) * 1000d *60d ); // 到JOB QUEUE 檢查是否有要執行的job的時間間隔(單位:分鐘) '20211015 13871,修正為*1000是秒, , *60才是分鐘 private int MonitorQueueDuration = (int)Math.Round(Conversions.ToDouble(modWIN.GetAppSettings("MonitorQueueDuration")) * 1000d * 60d); private const string JOB_FILE_NAME = "AutoLoaderJob_Base.xml"; #region 元件設計工具產生的程式碼 public Service1() : base() { // 此為元件設計工具所需的呼叫。 InitializeComponent(); // 在 InitializeComponent() 呼叫之後加入所有的初始化作業 } // UserService 覆寫 Dispose 以清除元件清單。 protected override void Dispose(bool disposing) { if (disposing) { if (components != null) { components.Dispose(); } } base.Dispose(disposing); } // 處理序的主進入點 [MTAThread()] public static void Main() { ServiceBase[] ServicesToRun; // 在同一個處理序中可以執行多個 NT 服務; 若要在這個處理序中 // 加入另一項服務,請修改以下各行 // 以建立第二個服務物件。例如, // // ServicesToRun = New System.ServiceProcess.ServiceBase () {New Service1, New MySecondUserService} // ServicesToRun = new ServiceBase[] { new Service1() }; //RunInteractive(ServicesToRun); //for debug Run(ServicesToRun); } private static void RunInteractive(ServiceBase[] servicesToRun) { var onStartMethod = typeof(ServiceBase).GetMethod("OnStart", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); foreach (ServiceBase service in servicesToRun) { Console.Write("Starting {0}...", service.ServiceName); onStartMethod.Invoke(service, new object[] { new string[] { } }); Console.Write("Started"); } Console.WriteLine("Press any key to stop the services"); Console.ReadKey(); var onStopMethod = typeof(ServiceBase).GetMethod("OnStop", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); foreach (ServiceBase service in servicesToRun) { Console.Write("Stopping {0}...", service.ServiceName); onStopMethod.Invoke(service, null); Console.WriteLine("Stopped"); } } // 為元件設計工具的必要項 private System.ComponentModel.IContainer components; // 注意: 以下為元件設計工具所需的程序 // 您可以使用元件設計工具進行修改, // 請勿使用程式碼編輯器進行修改。 private System.Timers.Timer _TimerCheckJobList; internal virtual System.Timers.Timer TimerCheckJobList { [MethodImpl(MethodImplOptions.Synchronized)] get { return _TimerCheckJobList; } [MethodImpl(MethodImplOptions.Synchronized)] set { if (_TimerCheckJobList != null) { _TimerCheckJobList.Elapsed -= TimerCheckJobList_Elapsed; } _TimerCheckJobList = value; if (_TimerCheckJobList != null) { _TimerCheckJobList.Elapsed += TimerCheckJobList_Elapsed; } } } private System.Timers.Timer _TimerCheckQueue; internal virtual System.Timers.Timer TimerCheckQueue { [MethodImpl(MethodImplOptions.Synchronized)] get { return _TimerCheckQueue; } [MethodImpl(MethodImplOptions.Synchronized)] set { if (_TimerCheckQueue != null) { _TimerCheckQueue.Elapsed -= TimerCheckQueue_Elapsed; } _TimerCheckQueue = value; if (_TimerCheckQueue != null) { _TimerCheckQueue.Elapsed += TimerCheckQueue_Elapsed; } } } [DebuggerStepThrough()] private void InitializeComponent() { this._TimerCheckJobList = new System.Timers.Timer(); this._TimerCheckQueue = new System.Timers.Timer(); ((System.ComponentModel.ISupportInitialize)(this._TimerCheckJobList)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this._TimerCheckQueue)).BeginInit(); // // _TimerCheckJobList // this._TimerCheckJobList.Interval = 2000D; this._TimerCheckJobList.Elapsed += new System.Timers.ElapsedEventHandler(this.TimerCheckJobList_Elapsed); // // _TimerCheckQueue // this._TimerCheckQueue.Interval = 3000D; this._TimerCheckQueue.Elapsed += new System.Timers.ElapsedEventHandler(this.TimerCheckQueue_Elapsed); // // Service1 // this.ServiceName = "MES AutoLoader Service (Production)"; ((System.ComponentModel.ISupportInitialize)(this._TimerCheckJobList)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this._TimerCheckQueue)).EndInit(); } #endregion protected override void OnStart(string[] args) { // // 在此加入啟動服務的程式碼,這個方法必須設定已啟動的 // // 事項,否則可能導致服務無法工作。 // //取出是否需要將Trace的Log產生檔案 try { string strTemp = modWIN.GetAppSettings("JobFilePath") == null ? "" : modWIN.GetAppSettings("JobFilePath"); if (strTemp.Contains(":")) strJobFilePath = Path.Combine(strTemp, JOB_FILE_NAME); else strJobFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, strTemp, JOB_FILE_NAME); } catch (Exception) { strJobFilePath = JOB_FILE_NAME; modWIN.WriteLog("defaultPath:" + strJobFilePath, iMESLog.iMESLogLevel.Trace); } try { blnTraceFile = bool.Parse(modWIN.GetAppSettings("TraceFile")); } catch (Exception ex) { blnTraceFile = false; } // //取出是否需要將Fail的Log產生檔案 try { blnLogFile = bool.Parse(modWIN.GetAppSettings("LogFile")); } catch (Exception ex) { blnLogFile = false; } // //取出是Trace產生檔案路徑 try { if (blnTraceFile == true) { string strTemp = modWIN.GetAppSettings("TraceFilePath") == null ? "" : modWIN.GetAppSettings("TraceFilePath"); if (strTemp.Contains(":")) strTraceFilePath = strTemp; else strTraceFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, strTemp); } } catch (Exception ex) { // 暫時 strTraceFilePath = @"C:\Temp\"; } // //取出是Log產生檔案路徑 try { if (blnLogFile == true) { string strTemp = modWIN.GetAppSettings("LogFilePath") == null ? "" : modWIN.GetAppSettings("LogFilePath"); if (strTemp.Contains(":")) strLogFilePath = strTemp; else strLogFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, strTemp); } } catch (Exception ex) { // 暫時 strLogFilePath = string.Empty; } if (blnTraceFile == true) { //funWriteTxtFile("Service Starting..."); modWIN.WriteLog("Service Starting...", iMESLog.iMESLogLevel.Trace); } dtAutoLoaderJob = new DataTable("AutoLoaderJob"); // 2021/8/10 Steven Mantis: 0097110: AuoLoader Service 錯誤攔截優化 try { //改成用读取节点的方式获取xml值 XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(strJobFilePath); XmlNodeList autoLoaderJobList = xmlDoc.GetElementsByTagName("AutoLoaderJob"); foreach (XmlNode autoLoaderJobNode in autoLoaderJobList) { DataRow drAdd; drAdd = dtAutoLoaderJob.NewRow(); foreach (XmlNode item in autoLoaderJobNode.ChildNodes) { if (!dtAutoLoaderJob.Columns.Contains(item.Name)) { dtAutoLoaderJob.Columns.Add(item.Name); } drAdd[item.Name] = funLoadXml(autoLoaderJobNode, item.Name); } dtAutoLoaderJob.Rows.Add(drAdd); } //dtAutoLoaderJob.ReadXmlSchema(strJobFilePath); //dtAutoLoaderJob.ReadXml(strJobFilePath); } catch (Exception ex) { modWIN.WriteLog("[" + Strings.Format(DateTime.Now, "yyyy/MM/dd HH:mm:ss") + "]" + "AutoLoaderJob_Base.xml不存在或格式不正確,請確認" + Constants.vbCrLf, iMESLog.iMESLogLevel.Error ); //modAutoLoader.WriteLogFile(strLogFilePath, "[" + Strings.Format(DateTime.Now, "yyyy/MM/dd HH:mm:ss") + "]" + "AutoLoaderJob_Base.xml不存在或格式不正確,請確認" + Constants.vbCrLf); } // //Init Status = 0 int i = 0; var loopTo = dtAutoLoaderJob.Rows.Count - 1; for (i = 0; i <= loopTo; i++) { dtAutoLoaderJob.Rows[i].BeginEdit(); dtAutoLoaderJob.Rows[i]["Status"] = 0; dtAutoLoaderJob.Rows[i].EndEdit(); } // '//Init Process // Call InitProcess() // 每隔n分鐘, 取回一次JOB LIST 到 JOB QUEUE TimerCheckJobList.Interval = MonitorjoblistDuration; TimerCheckJobList.Enabled = true; // 每隔n分鐘,到 JOB QUEUE 檢查是否有要執行的 TimerCheckQueue.Interval = MonitorQueueDuration; TimerCheckQueue.Enabled = true; } protected override void OnStop() { // //在此加入停止服務所需執行的終止程式碼。 dtAutoLoaderJob.WriteXml(strJobFilePath); dtAutoLoaderJob.Dispose(); TimerCheckJobList.Enabled = false; TimerCheckQueue.Enabled = false; if (blnTraceFile == true) { modWIN.WriteLog("Service Stopping...", iMESLog.iMESLogLevel.Trace); //funWriteTxtFile("Service Stopping..."); } } private void TimerCheckJobList_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { try { // //............................ // //每一秒鐘檢查是否有Job要執行 // //............................ // Me.TimerCheckJobList.Enabled = False if (blnTraceFile == true) { //funJobFile("Start CheckJobList"); modWIN.WriteLog("Start CheckJobList", iMESLog.iMESLogLevel.Trace); } // //變更需要執行的Job Status funGetJob2Queue(); if (blnTraceFile == true) { modWIN.WriteLog("End CheckJobList", iMESLog.iMESLogLevel.Trace); //funJobFile("End CheckJobList"); } TimerCheckJobList.Enabled = true; } catch (Exception ex) { modWIN.WriteLog("CheckJobList fail"+ex.Message , iMESLog.iMESLogLevel.Error ); TimerCheckJobList.Enabled = true; } } private void TimerCheckQueue_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { try { // //............................ // //每一秒鐘取出需要執行的Job // //............................ // Me.TimerCheckQueue.Enabled = False if (blnTraceFile == true) { modWIN.WriteLog("Start CheckQueue",iMESLog.iMESLogLevel.Trace ); // funQueueFile("Start CheckQueue"); } // //執行Job funRunJob(); if (blnTraceFile == true) { modWIN.WriteLog("End CheckQueue", iMESLog.iMESLogLevel.Trace); //funQueueFile("End CheckQueue"); } TimerCheckQueue.Enabled = true; } catch (Exception ex) { modWIN.WriteLog("CheckQueue fail:"+ ex.Message , iMESLog.iMESLogLevel.Error ); TimerCheckQueue.Enabled = true; } } #region Private Function /// /// 将status 改为1 待执行 /// public void funGetJob2Queue() { lock (this) { // //判斷目前的Job中是否需要排入執行 DataRow[] drSel; int idx = 0; var ArriveTime = DateTime.Now; try { // // drSel = dtAutoLoaderJob.Select("Status = 0"); // 未執行Job var loopTo = drSel.Length - 1; for (idx = 0; idx <= loopTo; idx++) { // 2023/4/21,Ning,129075: [博升] AutoLoader 日志报错, 執行頻率(Frequency)單位改為分鐘, 即秒*60 //if (Conversions.ToBoolean(Operators.ConditionalCompareObjectGreater(DateAndTime.DateDiff(DateInterval.Second, Conversions.ToDate(drSel[idx]["LastRunTime"]), ArriveTime), Conversions.ToInteger(drSel[idx]["Frequency"]) * 60, false))) //If DateDiff(DateInterval.Second, drSel(idx)("LastRunTime"), ArriveTime) > (drSel(idx)("Frequency") * 60) Then //检查上一次的时间与当配置的时间差 if (DateAndTime.DateDiff(DateInterval.Second, Convert.ToDateTime(drSel[idx]["LastRunTime"]), ArriveTime) > Convert.ToInt32(drSel[idx]["Frequency"]) * 60) { drSel[idx].BeginEdit(); drSel[idx]["Status"] = 1; // 待執行Job drSel[idx].EndEdit(); if (blnTraceFile == true) { //funJobFile(Conversions.ToString("JobNo:" + // drSel[idx]["JobNo"] + " -- " + drSel[idx]["LastRunTime"] + " ~ " + ArriveTime + " = " + DateAndTime.DateDiff(DateInterval.Second, Conversions.ToDate(drSel[idx]["LastRunTime"]), ArriveTime))); modWIN.WriteLog(Conversions.ToString("JobNo:" + drSel[idx]["JobNo"] + " -- " + drSel[idx]["LastRunTime"] + " ~ " + ArriveTime + " = " + DateAndTime.DateDiff(DateInterval.Second, Conversions.ToDate(drSel[idx]["LastRunTime"]), ArriveTime)), iMESLog.iMESLogLevel.Trace); } } } } catch (Exception ex) { //modAutoLoader.WriteLogFile(strLogFilePath, ex.Message + Constants.vbCrLf); modWIN.WriteLog("funGetJob2Queue fail :" +strLogFilePath + ex.Message, iMESLog.iMESLogLevel.Error ); } finally { // // drSel = null; } } } public void funRunJob() { lock (this) { DataRow[] drSel; int idx = 0; var ArriveTime = DateTime.Now; try { drSel = dtAutoLoaderJob.Select("Status = 1"); // 待執行Job if (blnTraceFile == true) { // funQueueFile("Queue Count:" + drSel.Length); modWIN.WriteLog("Queue Count:" + drSel.Length, iMESLog.iMESLogLevel.Trace); } var loopTo = drSel.Length - 1; for (idx = 0; idx <= loopTo; idx++) { if (blnTraceFile == true) { // funWriteTxtFile("Start Job..." + drSel[idx]["JobNo"].ToString()); modWIN.WriteLog("Start Job..." + drSel[idx]["JobNo"].ToString(), iMESLog.iMESLogLevel.Trace); } // //將Job改成執行中 drSel[idx].BeginEdit(); drSel[idx]["Status"] = 2; // 執行中 drSel[idx].EndEdit(); if (blnTraceFile == true) { // funWriteTxtFile("Status:Running"); modWIN.WriteLog("Status:Running", iMESLog.iMESLogLevel.Trace); } // //建立傳入執行緒之參數物件 var objJobData = new modAutoLoader.SomeStateType(); objJobData.SomeState(drSel[idx]["JobExecutionFile"].ToString(), drSel[idx]["JobNo"].ToString(), drSel[idx]["Jobfunction"].ToString(), drSel[idx]["SourcePath"].ToString(), drSel[idx]["DestinationPath"].ToString(), drSel[idx]["QueuePath"].ToString(), drSel[idx]["FailPath"].ToString(), strLogFilePath, Conversions.ToLong(drSel[idx]["SplitFileSize"].ToString()), Conversions.ToLong(drSel[idx]["SplitRecordsLimit"].ToString()), drSel[idx]["JobName"].ToString(), drSel[idx]["JobFunction"].ToString(), drSel[idx]["Parameter1"].ToString(), drSel[idx]["Parameter2"].ToString(), drSel[idx]["Parameter3"].ToString(), drSel[idx]["Parameter4"].ToString(), drSel[idx]["Parameter5"].ToString(), drSel[idx]["Parameter6"].ToString(), drSel[idx]["Parameter7"].ToString(), drSel[idx]["Parameter8"].ToString(), drSel[idx]["Parameter9"].ToString(), drSel[idx]["Parameter10"].ToString()); // //開始執行 if (System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(modAutoLoader.funProcessJob), objJobData) == false) { modWIN.WriteLog("Job Fail:" + drSel[idx]["JobNo"].ToString(), iMESLog.iMESLogLevel.Trace); // //funWriteTxtFile("Job Fail:" & drSel(idx)("JobNo").ToString) } // //將Job改成Queue drSel[idx].BeginEdit(); drSel[idx]["Status"] = 0; // Queue drSel[idx]["LastRunTime"] = Strings.Format(ArriveTime, "yyyy/MM/dd HH:mm:ss"); // 執行時間 drSel[idx].EndEdit(); if (blnTraceFile == true) { modWIN.WriteLog("Status:Complete," +"End Job..." + drSel[idx]["JobNo"].ToString(), iMESLog.iMESLogLevel.Trace); //funWriteTxtFile("Status:Complete"); //funWriteTxtFile("End Job..." + drSel[idx]["JobNo"].ToString()); } } } catch (Exception ex) { // // drSel = dtAutoLoaderJob.Select("Status = 2"); // 執行中 var loopTo = drSel.Length - 1; for (idx = 0; idx <= loopTo; idx++) { // //將Job改成待執行 drSel[idx].BeginEdit(); drSel[idx]["Status"] = 0; // Queue drSel[idx]["LastRunTime"] = Strings.Format(ArriveTime, "yyyy/MM/dd HH:mm:ss"); // 執行時間 drSel[idx].EndEdit(); } modWIN.WriteLog(ex.Message + Constants.vbCrLf, iMESLog.iMESLogLevel.Error ); //modAutoLoader.WriteLogFile(strLogFilePath, ex.Message + Constants.vbCrLf); } finally { drSel = null; } } } public void InitProcess() { try { // //開始執行 System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(modAutoLoader.funInitProcess)); } catch (Exception ex) { } } private string funWriteTxtFile(string WriteTxt) { try { string path = Path.Combine(strTraceFilePath, Strings.Format(DateTime.Now, "yyyyMMdd").ToString() + "_T3.Log"); if (!string.IsNullOrEmpty(strTraceFilePath) && !Directory.Exists(strTraceFilePath)) Directory.CreateDirectory(strTraceFilePath); lock (this) { var fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite); var w = new StreamWriter(fs); w.BaseStream.Seek(0L, SeekOrigin.End); w.WriteLine("日期時間:" + Strings.Format(DateTime.Now, "yyyy/MM/dd HH:mm:ss") + "--" + WriteTxt); w.Close(); fs.Close(); } } catch (Exception ex) { } return default(string); } private string funQueueFile(string WriteTxt) { try { string path = Path.Combine(strTraceFilePath, Strings.Format(DateTime.Now, "yyyyMMdd").ToString() + "_T1.Log"); if (!string.IsNullOrEmpty(strTraceFilePath) && !Directory.Exists(strTraceFilePath)) Directory.CreateDirectory(strTraceFilePath); lock (this) { var fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite); var w = new StreamWriter(fs); w.BaseStream.Seek(0L, SeekOrigin.End); w.WriteLine("日期時間:" + Strings.Format(DateTime.Now, "yyyy/MM/dd HH:mm:ss") + "--" + WriteTxt); w.Close(); fs.Close(); } } catch (Exception ex) { } return default(string); } private string funJobFile(string WriteTxt) { try { string path = Path.Combine(strTraceFilePath, Strings.Format(DateTime.Now, "yyyyMMdd").ToString() + "_T2.Log"); if (!string.IsNullOrEmpty(strTraceFilePath) && !Directory.Exists(strTraceFilePath)) Directory.CreateDirectory(strTraceFilePath); lock (this) { var fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite); var w = new StreamWriter(fs); w.BaseStream.Seek(0L, SeekOrigin.End); w.WriteLine("日期時間:" + Strings.Format(DateTime.Now, "yyyy/MM/dd HH:mm:ss") + "--" + WriteTxt); w.Close(); fs.Close(); } } catch (Exception ex) { } return default(string); } #endregion private string funLoadXml(XmlNode autoLoaderJobNode, string tag) { if (autoLoaderJobNode.SelectNodes(tag).Count > 0) { return autoLoaderJobNode.SelectSingleNode(tag).InnerText; } else { return ""; } } } }