From 045aa56d98c82fe4074b2ce5bdc3cc74c819bb3a Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Thu, 23 Nov 2017 15:12:28 -0500 Subject: [PATCH 1/2] Allows changing remote port without full restart --- TGS.CommandLine/ServiceCommands.cs | 3 +++ TGS.Interface/ServerInterface.cs | 38 +----------------------------- TGS.Server/EventID.cs | 4 ++++ TGS.Server/Server.cs | 24 +++++++++++++++++-- 4 files changed, 30 insertions(+), 39 deletions(-) diff --git a/TGS.CommandLine/ServiceCommands.cs b/TGS.CommandLine/ServiceCommands.cs index 833469d0c8..8ec2cd221b 100644 --- a/TGS.CommandLine/ServiceCommands.cs +++ b/TGS.CommandLine/ServiceCommands.cs @@ -388,6 +388,9 @@ namespace TGS.CommandLine OutputProc(res); return ExitCode.ServerError; } + + Interface.Dispose(); //close the channels to prevent holding the service open + OutputProc("Change will be applied after service restart"); return ExitCode.Normal; } diff --git a/TGS.Interface/ServerInterface.cs b/TGS.Interface/ServerInterface.cs index e92e630e19..d1bfec48ff 100644 --- a/TGS.Interface/ServerInterface.cs +++ b/TGS.Interface/ServerInterface.cs @@ -453,48 +453,12 @@ namespace TGS.Interface } } - #region IDisposable Support - /// - /// To detect redundant calls - /// - private bool disposedValue = false; - - /// - /// Implements the pattern. Calls - /// - /// if was called manually, if it was from the finalizer - void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - CloseAllChannels(true); - } - - // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. - // TODO: set large fields to null. - - disposedValue = true; - } - } - - // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. - // ~Interface() { - // // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - // Dispose(false); - // } - /// /// Implements the pattern /// public void Dispose() { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - // TODO: uncomment the following line if the finalizer is overridden above. - // GC.SuppressFinalize(this); + CloseAllChannels(true); } - #endregion } } diff --git a/TGS.Server/EventID.cs b/TGS.Server/EventID.cs index 5fd0a44696..e021b1112c 100644 --- a/TGS.Server/EventID.cs +++ b/TGS.Server/EventID.cs @@ -331,5 +331,9 @@ namespace TGS.Server /// Warning: When a testmerge commit failed to be published /// ReferencePush = 7700, + /// + /// Error: When restarting the root service host and an unrecoverable error was encountered + /// + RootHostRestartFailure = 7800, } } diff --git a/TGS.Server/Server.cs b/TGS.Server/Server.cs index b500bf3fa0..3e7e0d8138 100644 --- a/TGS.Server/Server.cs +++ b/TGS.Server/Server.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; -using System.Collections.Specialized; using System.Diagnostics; using System.IO; using System.Reflection; using System.Security.Principal; using System.ServiceModel; +using System.Threading.Tasks; using TGS.Interface; using TGS.Interface.Components; @@ -104,6 +104,25 @@ namespace TGS.Server OnlineAllHosts(); } + /// + /// Attempts to reload + /// + void RestartHost() + { + lock (this) + try + { + serviceHost.Close(); + Config.Save(DefaultConfigDirectory); + SetupService(); + serviceHost.Open(); + } + catch (Exception e) + { + Logger.WriteError(String.Format("An unrecoverable error occurred while attempting to restart the root ServiceHost! Error: {0}", e.ToString()), EventID.RootHostRestartFailure, LoggingID); + } + } + /// /// Enumerates configured s. Detaches those that fail to load /// @@ -359,8 +378,8 @@ namespace TGS.Server Logger.WriteError(e.ToString(), EventID.ServiceShutdownFail, LoggingID); } serviceHost.Close(); + Config.Save(DefaultConfigDirectory); } - Config.Save(DefaultConfigDirectory); } /// @@ -385,6 +404,7 @@ namespace TGS.Server if (port == 0) return "Cannot bind to port 0"; Config.RemoteAccessPort = port; + Task.Factory.StartNew(() => RestartHost()); return null; } From d83c20f61494e16cc5672722289e49ddbbf0d4c2 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Thu, 23 Nov 2017 15:30:38 -0500 Subject: [PATCH 2/2] More cleanup around remote access port switching --- TGS.CommandLine/ServiceCommands.cs | 3 +- TGS.Server/EventID.cs | 11 +++++- TGS.Server/Server.cs | 60 +++++++++++++++++++++++++----- 3 files changed, 61 insertions(+), 13 deletions(-) diff --git a/TGS.CommandLine/ServiceCommands.cs b/TGS.CommandLine/ServiceCommands.cs index 8ec2cd221b..d68476b4fb 100644 --- a/TGS.CommandLine/ServiceCommands.cs +++ b/TGS.CommandLine/ServiceCommands.cs @@ -390,8 +390,7 @@ namespace TGS.CommandLine } Interface.Dispose(); //close the channels to prevent holding the service open - - OutputProc("Change will be applied after service restart"); + return ExitCode.Normal; } } diff --git a/TGS.Server/EventID.cs b/TGS.Server/EventID.cs index e021b1112c..8a011c67f2 100644 --- a/TGS.Server/EventID.cs +++ b/TGS.Server/EventID.cs @@ -332,8 +332,15 @@ namespace TGS.Server /// ReferencePush = 7700, /// - /// Error: When restarting the root service host and an unrecoverable error was encountered + /// Info: When the root ServiceHost has been restarted + /// Error: When restarting the root ServiceHost and an unrecoverable error was encountered /// - RootHostRestartFailure = 7800, + RootHostRestart = 7800, + /// + /// Info: When an operation to change the remote access port begins + /// Warning: When a port change operation fails and a revert is attempted + /// Error: When the config could not be saved when attempting to change the remote access port + /// + RemoteAccessPortChange = 7900, } } diff --git a/TGS.Server/Server.cs b/TGS.Server/Server.cs index 3e7e0d8138..412e4dc24b 100644 --- a/TGS.Server/Server.cs +++ b/TGS.Server/Server.cs @@ -104,22 +104,37 @@ namespace TGS.Server OnlineAllHosts(); } + void SafeCloseServiceHost(ServiceHost host) + { + try + { + host.Close(); + } + catch + { + host.Abort(); + } + } + /// /// Attempts to reload /// - void RestartHost() + /// on success, otherwise + bool RestartHost() { lock (this) try { - serviceHost.Close(); - Config.Save(DefaultConfigDirectory); + SafeCloseServiceHost(serviceHost); SetupService(); serviceHost.Open(); + Logger.WriteInfo("Root ServiceHost restarted", EventID.RootHostRestart, LoggingID); + return true; } catch (Exception e) { - Logger.WriteError(String.Format("An unrecoverable error occurred while attempting to restart the root ServiceHost! Error: {0}", e.ToString()), EventID.RootHostRestartFailure, LoggingID); + Logger.WriteError(String.Format("An unrecoverable error occurred while attempting to restart the root ServiceHost! Error: {0}", e.ToString()), EventID.RootHostRestart, LoggingID); + return false; } } @@ -368,7 +383,7 @@ namespace TGS.Server { var host = I.Value; var instance = (Instance)host.SingletonInstance; - host.Close(); + SafeCloseServiceHost(host); instance.Dispose(); UnlockLoggingID(instance.LoggingID); } @@ -377,7 +392,7 @@ namespace TGS.Server { Logger.WriteError(e.ToString(), EventID.ServiceShutdownFail, LoggingID); } - serviceHost.Close(); + SafeCloseServiceHost(serviceHost); Config.Save(DefaultConfigDirectory); } } @@ -403,8 +418,35 @@ namespace TGS.Server { if (port == 0) return "Cannot bind to port 0"; - Config.RemoteAccessPort = port; - Task.Factory.StartNew(() => RestartHost()); + ushort orig_port; + lock (this) + { + orig_port = Config.RemoteAccessPort; + if (port == orig_port) + return null; + try + { + //save first just in case + Config.Save(DefaultConfigDirectory); + } + catch (Exception e) + { + Logger.WriteError(e.ToString(), EventID.RemoteAccessPortChange, LoggingID); + return String.Format("An error occurred: {0}", e.ToString()); + } + Logger.WriteInfo(String.Format("Changing remote access port from {0} to {1}", orig_port, port), EventID.RemoteAccessPortChange, LoggingID); + Config.RemoteAccessPort = port; + } + Task.Factory.StartNew(() => + { + lock (this) + if (!RestartHost()) + { + Logger.WriteWarning(String.Format("Port change to {0} failed, Reverting to port {1}!", port, orig_port), EventID.RemoteAccessPortChange, LoggingID); + Config.RemoteAccessPort = orig_port; + RestartHost(); + } + }); return null; } @@ -583,7 +625,7 @@ namespace TGS.Server var host = hosts[Name]; hosts.Remove(Name); var inst = (Instance)host.SingletonInstance; - host.Close(); + SafeCloseServiceHost(host); path = inst.ServerDirectory(); inst.Offline(); inst.Dispose();