using System; using System.Diagnostics; using System.ServiceProcess; using AppServerWatchDogService.Enums; using System.Runtime.InteropServices; using System.Threading; using System.IO.Pipes; using System.IO; using System.Timers; using System.Threading.Tasks; namespace AppServerWatchDogService { // sc create AppServerWatchDogService binPath="E:\WorkSpace_cSharp\SafeDispatch_v4\AppServerWatchDogService\bin\Debug\AppServerWatchDogService.exe" start= auto public enum ServiceState { SERVICE_STOPPED = 0x00000001, SERVICE_START_PENDING = 0x00000002, SERVICE_STOP_PENDING = 0x00000003, SERVICE_RUNNING = 0x00000004, SERVICE_CONTINUE_PENDING = 0x00000005, SERVICE_PAUSE_PENDING = 0x00000006, SERVICE_PAUSED = 0x00000007, } [StructLayout(LayoutKind.Sequential)] public struct ServiceStatus { public int dwServiceType; public ServiceState dwCurrentState; public int dwControlsAccepted; public int dwWin32ExitCode; public int dwServiceSpecificExitCode; public int dwCheckPoint; public int dwWaitHint; }; public partial class AppServerWatchDogService : ServiceBase { #region Config Values public static Boolean restartTCPService = false; public static Boolean monitorAppServer = false; #endregion private static bool isRunning = false; private static int smallNrOfWorkersCount = 0; public static int tries = 0; public static String serviceLocation = System.Reflection.Assembly.GetExecutingAssembly().Location; public static String serviceFolder = serviceLocation.Substring(0, serviceLocation.LastIndexOf('\\')); public static String appServerFolder = serviceFolder.Substring(0, serviceFolder.LastIndexOf('\\')) + "\\AppServer"; public static String batFile = appServerFolder + "\\SafeDispatch-StartUp.bat"; [DllImport("advapi32.dll", SetLastError = true)] private static extern bool SetServiceStatus(IntPtr handle, ref ServiceStatus serviceStatus); public AppServerWatchDogService() { InitializeComponent(); eventLog1 = new EventLog(); if (!EventLog.SourceExists("MySource")) { EventLog.CreateEventSource("MySource", "MyNewLog"); } eventLog1.Source = "MySource"; eventLog1.Log = "MyNewLog"; } protected override void OnStart(string[] args) { // Update the service state to Start Pending. ServiceStatus serviceStatus = new ServiceStatus(); serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING; serviceStatus.dwWaitHint = 100000; SetServiceStatus(this.ServiceHandle, ref serviceStatus); System.Timers.Timer timer = new System.Timers.Timer(); timer.Interval = 60000; // 60 seconds timer.Elapsed += new ElapsedEventHandler(this.OnTimer); timer.Start(); WriteEventLog(Program.COMPANY, "WatchDog Started!!!", EventLogEntryType.Information, (Int32)EventId.EVENT_WATCHDOG); // Update the service state to Running. serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING; SetServiceStatus(this.ServiceHandle, ref serviceStatus); if (!ConfigHelper.HasRestartTCPService || !ConfigHelper.HasTCPServiceName) { WriteEventLog(Program.COMPANY, "AppSettings does not contain key \"restartTCPService\" or \"serviceName\"", EventLogEntryType.Error, (int)EventId.EVENT_WATCHDOG); } else { restartTCPService = ConfigHelper.RestartTCPService; } if (!ConfigHelper.HasAppServerMonitor) { WriteEventLog(Program.COMPANY, "AppSettings does not contain key \"monitorAppServer\"", EventLogEntryType.Error, (int)EventId.EVENT_WATCHDOG); } else { monitorAppServer = ConfigHelper.AppServerMonitor; } if (!File.Exists(batFile) && ConfigHelper.AppServerMonitor) CreateBatFile(batFile); if (restartTCPService) StartTCPThread(); if (monitorAppServer) StartWatchDog(); } protected override void OnStop() { if (File.Exists(batFile)) File.Delete(batFile); isRunning = false; WriteEventLog(Program.COMPANY, "WatchDog STOPPED!!!", EventLogEntryType.Warning, (Int32)EventId.EVENT_WATCHDOG); } public void OnTimer(object sender, ElapsedEventArgs args) { // TODO: Insert monitoring activities here. } public void StartTCPThread() { Task.Factory.StartNew(() => { RestartTCPClient.Main(); }); } public void StartWatchDog() { isRunning = true; Thread t = new Thread(WatchDogWorker); t.IsBackground = true; t.Start(); } private static void WatchDogWorker() { isRunning = true; int count = 0; int timeoutBeforeStartingToMonitorInSec = ConfigHelper.TimeoutBeforeStartingToMonitorSec; // wait 10 seconds before starting to check for AppServer while (count++ < timeoutBeforeStartingToMonitorInSec * 10) { if (!isRunning) return; Thread.Sleep(100); } count = 0; while (isRunning) { Thread.Sleep(100); if (count++ > 30 && isRunning) { using (NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", "appServerPipe", PipeDirection.InOut)) { try { // Connect to the pipe or wait until the pipe is available. //WriteEventLog(Program.COMPANY, "Attempting to connect to pipe...", EventLogEntryType.Information, (Int32)EventId.EVENT_WATCHDOG); pipeClient.Connect(1000); //WriteEventLog(Program.COMPANY, "Connected to pipe.", EventLogEntryType.Information, (Int32)EventId.EVENT_WATCHDOG); WriteEventLog(Program.COMPANY, String.Format("There are currently {0} pipe server instances open.", pipeClient.NumberOfServerInstances), EventLogEntryType.Information, (Int32)EventId.EVENT_WATCHDOG); using (StreamReader sr = new StreamReader(pipeClient)) { // Display the read text to the console string temp; while ((temp = sr.ReadLine()) != null) { //WriteEventLog(Program.COMPANY, String.Format("Received from server: {0}", temp), EventLogEntryType.Information, (Int32)EventId.EVENT_WATCHDOG); String[] split = temp.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries); int numberOfWorkersQueueCount = 0; if (split.Length > 0) Int32.TryParse(split[0], out numberOfWorkersQueueCount); if (numberOfWorkersQueueCount < 200) smallNrOfWorkersCount++; // restart app server if for the last 5 iterations the number of gps workers was small if (smallNrOfWorkersCount >= 5) { WriteEventLog(Program.COMPANY, String.Format("WatchDog detected slow GPS queue polling : " + smallNrOfWorkersCount), EventLogEntryType.Warning, (Int32)EventId.EVENT_WATCHDOG); RestartAppServer(); } } } } catch (Exception ex) { tries++; WriteEventLog(Program.COMPANY, String.Format("WatchDog unable to connect to namedpipe!!! Tries numeber: " + tries.ToString() + Environment.NewLine + ex.ToString()), EventLogEntryType.Error, (Int32)EventId.EVENT_WATCHDOG); if (tries == ConfigHelper.NumberOfMissingPingsWithAppServerAllowed) { RestartAppServer(); tries = 0; } } } count = 0; } } } private static void RestartAppServer() { try { // the name of the application to launch; // to launch an application using the full command path simply escape // the path with quotes, for example to launch firefox.exe: // String applicationName = "\"C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe\""; String applicationName = batFile; // launch the application ApplicationLoader.PROCESS_INFORMATION procInfo; ApplicationLoader.StartProcessAndBypassUAC(applicationName, out procInfo); WriteEventLog(Program.COMPANY, "AppServer restarted using: " + batFile.ToString(), EventLogEntryType.Information, (Int32)EventId.EVENT_WATCHDOG); } catch (Exception ex) { WriteEventLog(Program.COMPANY, appServerFolder + "\\" + "AppServer.exe", EventLogEntryType.Error, (Int32)EventId.EVENT_WATCHDOG); WriteEventLog(Program.COMPANY, ex.ToString(), EventLogEntryType.Error, (Int32)EventId.EVENT_WATCHDOG); } } public static void WriteEventLog(String source, String content, EventLogEntryType type, Int32 eventId) { try { if (!EventLog.SourceExists(source)) EventLog.CreateEventSource(source, "Application"); EventLog.WriteEntry(source, content, type, eventId); } catch (Exception ex) { throw ex; } } private void CreateBatFile(string batLocation) { try { using (StreamWriter sw = new StreamWriter(batLocation)) { sw.WriteLine("@ECHO off"); sw.WriteLine("echo Starting AppServer"); sw.WriteLine($"cd /d \"{appServerFolder}\""); sw.WriteLine("start AppServer.exe -c -l"); } WriteEventLog(Program.COMPANY, ".bat file created at: " + batFile.ToString(), EventLogEntryType.Information, (Int32)EventId.EVENT_WATCHDOG); } catch (Exception ex) { WriteEventLog(Program.COMPANY, "Failed to create .bat file because: " + Environment.NewLine + ex.ToString(), EventLogEntryType.Error, (Int32)EventId.EVENT_WATCHDOG); } } } }