294 lines
12 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|