Merge pull request #412 from tgstation/402-AutoRestart

Allows changing remote port without full restart
This commit is contained in:
Jordan Brown
2017-11-23 15:50:26 -05:00
committed by GitHub
4 changed files with 83 additions and 44 deletions
+3 -1
View File
@@ -388,7 +388,9 @@ namespace TGS.CommandLine
OutputProc(res);
return ExitCode.ServerError;
}
OutputProc("Change will be applied after service restart");
Interface.Dispose(); //close the channels to prevent holding the service open
return ExitCode.Normal;
}
}
+1 -37
View File
@@ -453,48 +453,12 @@ namespace TGS.Interface
}
}
#region IDisposable Support
/// <summary>
/// To detect redundant <see cref="Dispose(bool)"/> calls
/// </summary>
private bool disposedValue = false;
/// <summary>
/// Implements the <see cref="IDisposable"/> pattern. Calls <see cref="CloseAllChannels"/>
/// </summary>
/// <param name="disposing"><see langword="true"/> if <see cref="Dispose()"/> was called manually, <see langword="false"/> if it was from the finalizer</param>
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);
// }
/// <summary>
/// Implements the <see cref="IDisposable"/> pattern
/// </summary>
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
}
}
+11
View File
@@ -331,5 +331,16 @@ namespace TGS.Server
/// Warning: When a testmerge commit failed to be published
/// </summary>
ReferencePush = 7700,
/// <summary>
/// Info: When the root ServiceHost has been restarted
/// Error: When restarting the root ServiceHost and an unrecoverable error was encountered
/// </summary>
RootHostRestart = 7800,
/// <summary>
/// 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
/// </summary>
RemoteAccessPortChange = 7900,
}
}
+68 -6
View File
@@ -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,40 @@ namespace TGS.Server
OnlineAllHosts();
}
void SafeCloseServiceHost(ServiceHost host)
{
try
{
host.Close();
}
catch
{
host.Abort();
}
}
/// <summary>
/// Attempts to reload <see cref="serviceHost"/>
/// </summary>
/// <returns><see langword="true"/> on success, <see langword="false"/> otherwise</returns>
bool RestartHost()
{
lock (this)
try
{
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.RootHostRestart, LoggingID);
return false;
}
}
/// <summary>
/// Enumerates configured <see cref="IInstanceConfig"/>s. Detaches those that fail to load
/// </summary>
@@ -349,7 +383,7 @@ namespace TGS.Server
{
var host = I.Value;
var instance = (Instance)host.SingletonInstance;
host.Close();
SafeCloseServiceHost(host);
instance.Dispose();
UnlockLoggingID(instance.LoggingID);
}
@@ -358,9 +392,9 @@ namespace TGS.Server
{
Logger.WriteError(e.ToString(), EventID.ServiceShutdownFail, LoggingID);
}
serviceHost.Close();
SafeCloseServiceHost(serviceHost);
Config.Save(DefaultConfigDirectory);
}
Config.Save(DefaultConfigDirectory);
}
/// <inheritdoc />
@@ -384,7 +418,35 @@ namespace TGS.Server
{
if (port == 0)
return "Cannot bind to port 0";
Config.RemoteAccessPort = port;
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;
}
@@ -563,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();