SafeDispatch/AppServerWatchDogService/AppServerWatchDogService.cs
2024-02-22 18:43:59 +02:00

294 lines
12 KiB
C#

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);
}
}
}
}