/// <summary> /// Event handler for service stopping operation. /// </summary> /// <param name="sender">Event source.</param> /// <param name="e">Event arguments.</param> /// <remarks> /// Time-series framework uses this handler to un-wire events and dispose of system objects. /// </remarks> protected virtual void ServiceStoppingHandler(object sender, EventArgs e) { // Stop generation zero garbage collection timer if (m_gcGenZeroTimer != null) { m_gcGenZeroTimer.Enabled = false; m_gcGenZeroTimer.Elapsed -= m_gcGenZeroTimer_Elapsed; m_gcGenZeroTimer.Dispose(); } m_gcGenZeroTimer = null; // Dispose system health exporter if (m_healthExporter != null) { m_healthExporter.Enabled = false; m_serviceHelper.ServiceComponents.Remove(m_healthExporter); m_healthExporter.Dispose(); m_healthExporter.StatusMessage -= m_iaonSession.StatusMessageHandler; m_healthExporter.ProcessException -= m_iaonSession.ProcessExceptionHandler; } m_healthExporter = null; // Dispose system status exporter if (m_statusExporter != null) { m_statusExporter.Enabled = false; m_serviceHelper.ServiceComponents.Remove(m_statusExporter); m_statusExporter.Dispose(); m_statusExporter.StatusMessage -= m_iaonSession.StatusMessageHandler; m_statusExporter.ProcessException -= m_iaonSession.ProcessExceptionHandler; } m_statusExporter = null; // Dispose Iaon session if (m_iaonSession != null) { m_serviceHelper.ServiceComponents.Remove(m_iaonSession.InputAdapters); m_serviceHelper.ServiceComponents.Remove(m_iaonSession.ActionAdapters); m_serviceHelper.ServiceComponents.Remove(m_iaonSession.OutputAdapters); m_iaonSession.Dispose(); m_iaonSession.StatusMessage -= m_iaonSession_StatusMessage; m_iaonSession.ProcessException -= m_iaonSession_ProcessException; } m_iaonSession = null; m_serviceHelper.ServiceStarting -= ServiceStartingHandler; m_serviceHelper.ServiceStarted -= ServiceStartedHandler; m_serviceHelper.ServiceStopping -= ServiceStoppingHandler; if (m_serviceHelper.StatusLog != null) { m_serviceHelper.StatusLog.Flush(); m_serviceHelper.StatusLog.LogException -= LogExceptionHandler; } if (m_serviceHelper.ErrorLogger != null && m_serviceHelper.ErrorLogger.ErrorLog != null) { m_serviceHelper.ErrorLogger.ErrorLog.Flush(); m_serviceHelper.ErrorLogger.ErrorLog.LogException -= LogExceptionHandler; } if ((object)m_configurationCacheComplete != null) { // Release any waiting threads before disposing wait handle m_configurationCacheComplete.Set(); m_configurationCacheComplete.Dispose(); } m_configurationCacheComplete = null; // Unattach from handler for unobserved task exceptions TaskScheduler.UnobservedTaskException -= TaskScheduler_UnobservedTaskException; }
/// <summary> /// Event handler for service started operation. /// </summary> /// <param name="sender">Event source.</param> /// <param name="e">Event arguments.</param> /// <remarks> /// Time-series framework uses this handler to handle initialization of system objects. /// </remarks> protected virtual void ServiceStartedHandler(object sender, EventArgs e) { // Define a line of asterisks for emphasis string stars = new string('*', 79); // Log startup information m_serviceHelper.UpdateStatus( UpdateType.Information, "\r\n\r\n{0}\r\n\r\n" + "Node {{{1}}} Initializing\r\n\r\n" + " System Time: {2} UTC\r\n\r\n" + " Current Path: {3}\r\n\r\n" + " Machine Name: {4}\r\n\r\n" + " OS Version: {5}\r\n\r\n" + " Product Name: {6}\r\n\r\n" + " Working Memory: {7}\r\n\r\n" + " Execution Mode: {8}-bit\r\n\r\n" + " Processors: {9}\r\n\r\n" + " GC Server Mode: {10}\r\n\r\n" + " GC Latency Mode: {11}\r\n\r\n" + " Process Account: {12}\\{13}\r\n\r\n" + "{14}\r\n", stars, m_iaonSession.NodeID, DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff"), FilePath.TrimFileName(FilePath.RemovePathSuffix(FilePath.GetAbsolutePath("")), 61), Environment.MachineName, Environment.OSVersion.VersionString, Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductName", null).ToNonNullString("<Unavailable>"), SI2.ToScaledIECString(Environment.WorkingSet, 3, "B"), IntPtr.Size * 8, Environment.ProcessorCount, GCSettings.IsServerGC, GCSettings.LatencyMode, Environment.UserDomainName, Environment.UserName, stars); // Create health exporter m_healthExporter = new MultipleDestinationExporter("HealthExporter", Timeout.Infinite); m_healthExporter.Initialize(new ExportDestination[] { new ExportDestination(FilePath.GetAbsolutePath("Health.txt"), false) }); m_healthExporter.StatusMessage += m_iaonSession.StatusMessageHandler; m_healthExporter.ProcessException += m_iaonSession.ProcessExceptionHandler; m_serviceHelper.ServiceComponents.Add(m_healthExporter); // Create status exporter m_statusExporter = new MultipleDestinationExporter("StatusExporter", Timeout.Infinite); m_statusExporter.Initialize(new ExportDestination[] { new ExportDestination(FilePath.GetAbsolutePath("Status.txt"), false) }); m_statusExporter.StatusMessage += m_iaonSession.StatusMessageHandler; m_statusExporter.ProcessException += m_iaonSession.ProcessExceptionHandler; m_serviceHelper.ServiceComponents.Add(m_statusExporter); // Define scheduled service processes m_serviceHelper.AddScheduledProcess(HealthMonitorProcessHandler, "HealthMonitor", "* * * * *"); // Every minute m_serviceHelper.AddScheduledProcess(StatusExportProcessHandler, "StatusExport", "*/30 * * * *"); // Every 30 minutes // Add key Iaon collections as service components m_serviceHelper.ServiceComponents.Add(m_iaonSession.InputAdapters); m_serviceHelper.ServiceComponents.Add(m_iaonSession.ActionAdapters); m_serviceHelper.ServiceComponents.Add(m_iaonSession.OutputAdapters); // Define remote client requests (i.e., console commands) m_serviceHelper.ClientRequestHandlers.Add(new ClientRequestHandler("List", "Displays status for specified adapter or collection", ListRequestHandler)); m_serviceHelper.ClientRequestHandlers.Add(new ClientRequestHandler("Connect", "Connects (or starts) specified adapter", StartRequestHandler)); m_serviceHelper.ClientRequestHandlers.Add(new ClientRequestHandler("Disconnect", "Disconnects (or stops) specified adapter", StopRequestHandler)); m_serviceHelper.ClientRequestHandlers.Add(new ClientRequestHandler("Invoke", "Invokes a command for specified adapter", InvokeRequestHandler)); m_serviceHelper.ClientRequestHandlers.Add(new ClientRequestHandler("ListCommands", "Displays possible commands for specified adapter", ListCommandsRequestHandler)); m_serviceHelper.ClientRequestHandlers.Add(new ClientRequestHandler("Initialize", "Initializes specified adapter or collection", InitializeRequestHandler)); m_serviceHelper.ClientRequestHandlers.Add(new ClientRequestHandler("ReloadConfig", "Manually reloads the system configuration", ReloadConfigRequstHandler)); m_serviceHelper.ClientRequestHandlers.Add(new ClientRequestHandler("UpdateConfigFile", "Updates an option in the configuration file", UpdateConfigFileRequestHandler)); m_serviceHelper.ClientRequestHandlers.Add(new ClientRequestHandler("Authenticate", "Authenticates network shares for health and status exports", AuthenticateRequestHandler)); m_serviceHelper.ClientRequestHandlers.Add(new ClientRequestHandler("Restart", "Attempts to restart the host service", RestartServiceHandler)); m_serviceHelper.ClientRequestHandlers.Add(new ClientRequestHandler("RefreshRoutes", "Spawns request to recalculate routing tables", RefreshRoutesRequestHandler)); m_serviceHelper.ClientRequestHandlers.Add(new ClientRequestHandler("TemporalSupport", "Detemines if any adapters support temporal processing", TemporalSupportRequestHandler)); try { // Start system initialization on an independent thread so that service responds in a timely fashion... ThreadPool.QueueUserWorkItem(InitializeSystem); } catch (Exception ex) { // Process exception for logging DisplayStatusMessage("Failed to queue system initialization due to exception: {0}", UpdateType.Alarm, ex.Message); m_serviceHelper.ErrorLogger.Log(ex); } }