diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs
index c06f18044c..343e7eec37 100644
--- a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs
+++ b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs
@@ -39,6 +39,11 @@ namespace Tgstation.Server.Host.Components.Session
///
CompileJob CompileJob { get; }
+ ///
+ /// Gets the associated with the .
+ ///
+ ReattachInformation ReattachInformation { get; }
+
///
/// If the port should be rotated off when the world reboots.
///
@@ -67,8 +72,8 @@ namespace Tgstation.Server.Host.Components.Session
///
/// Releases the without terminating it. Also calls .
///
- /// A resulting in which can be used to create a new .
- Task Release();
+ /// A representing the running operation.
+ Task Release();
///
/// Sends a command to DreamDaemon through /world/Topic().
diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs b/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs
index 4dc2f4c0ab..3028e6daf4 100644
--- a/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs
+++ b/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs
@@ -22,5 +22,12 @@ namespace Tgstation.Server.Host.Components.Session
/// The for the operation.
/// A resulting in the stored if any.
Task Load(CancellationToken cancellationToken);
+
+ ///
+ /// Clear any stored .
+ ///
+ /// The for the operation.
+ /// A representing the running operation.
+ Task Clear(CancellationToken cancellationToken);
}
}
diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs
index a7a5d71478..eb8969db4c 100644
--- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs
+++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs
@@ -27,7 +27,7 @@ namespace Tgstation.Server.Host.Components.Session
sealed class SessionController : ISessionController, IBridgeHandler, IChannelSink
{
///
- public DMApiParameters DMApiParameters => reattachInformation;
+ public DMApiParameters DMApiParameters => ReattachInformation;
///
public ApiValidationStatus ApiValidationStatus
@@ -41,10 +41,10 @@ namespace Tgstation.Server.Host.Components.Session
}
///
- public Models.CompileJob CompileJob => reattachInformation.Dmb.CompileJob;
+ public Models.CompileJob CompileJob => ReattachInformation.Dmb.CompileJob;
///
- public RebootState RebootState => reattachInformation.RebootState;
+ public RebootState RebootState => ReattachInformation.RebootState;
///
public Version DMApiVersion { get; private set; }
@@ -68,12 +68,12 @@ namespace Tgstation.Server.Host.Components.Session
public Task OnPrime => primeTcs.Task;
///
- public bool DMApiAvailable => reattachInformation.Dmb.CompileJob.DMApiVersion?.Major == DMApiConstants.InteropVersion.Major;
+ public bool DMApiAvailable => ReattachInformation.Dmb.CompileJob.DMApiVersion?.Major == DMApiConstants.InteropVersion.Major;
///
- /// The up to date .
+ /// The up to date .
///
- readonly ReattachInformation reattachInformation;
+ public ReattachInformation ReattachInformation { get; }
///
/// The that completes when DD makes it's first bridge request.
@@ -173,7 +173,7 @@ namespace Tgstation.Server.Host.Components.Session
///
/// Initializes a new instance of the class.
///
- /// The value of .
+ /// The value of .
/// The owning .
/// The value of .
/// The value of .
@@ -203,7 +203,7 @@ namespace Tgstation.Server.Host.Components.Session
bool reattached,
bool apiValidate)
{
- this.reattachInformation = reattachInformation ?? throw new ArgumentNullException(nameof(reattachInformation));
+ ReattachInformation = reattachInformation ?? throw new ArgumentNullException(nameof(reattachInformation));
this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata));
this.process = process ?? throw new ArgumentNullException(nameof(process));
this.byondLock = byondLock ?? throw new ArgumentNullException(nameof(byondLock));
@@ -277,7 +277,7 @@ namespace Tgstation.Server.Host.Components.Session
process.Dispose();
bridgeRegistration?.Dispose();
- reattachInformation.Dmb?.Dispose(); // will be null when released
+ ReattachInformation.Dmb?.Dispose(); // will be null when released
chatTrackingContext.Dispose();
reattachTopicCts.Dispose();
@@ -346,13 +346,13 @@ namespace Tgstation.Server.Host.Components.Session
var currentPort = parameters.CurrentPort.Value;
if (!nextPort.HasValue)
- reattachInformation.Port = parameters.CurrentPort.Value; // not ready yet, so what we'll do is accept the random port DD opened on for now and change it later when we decide to
+ ReattachInformation.Port = parameters.CurrentPort.Value; // not ready yet, so what we'll do is accept the random port DD opened on for now and change it later when we decide to
else
{
// nextPort is ready, tell DD to switch to that
// if it fails it'll kill itself
response.NewPort = nextPort.Value;
- reattachInformation.Port = nextPort.Value;
+ ReattachInformation.Port = nextPort.Value;
nextPort = null;
// we'll also get here from SetPort so complete that task
@@ -398,12 +398,12 @@ namespace Tgstation.Server.Host.Components.Session
response.RuntimeInformation = new RuntimeInformation(
chatTrackingContext,
- reattachInformation.Dmb,
- reattachInformation.RuntimeInformation.ServerVersion,
- reattachInformation.RuntimeInformation.InstanceName,
- reattachInformation.RuntimeInformation.SecurityLevel,
- reattachInformation.RuntimeInformation.ServerPort,
- reattachInformation.RuntimeInformation.ApiValidateOnly);
+ ReattachInformation.Dmb,
+ ReattachInformation.RuntimeInformation.ServerVersion,
+ ReattachInformation.RuntimeInformation.InstanceName,
+ ReattachInformation.RuntimeInformation.SecurityLevel,
+ ReattachInformation.RuntimeInformation.ServerPort,
+ ReattachInformation.RuntimeInformation.ApiValidateOnly);
// Load custom commands
chatTrackingContext.CustomCommands = parameters.CustomCommands;
@@ -436,19 +436,18 @@ namespace Tgstation.Server.Host.Components.Session
public void EnableCustomChatCommands() => chatTrackingContext.Active = DMApiAvailable;
///
- public async Task Release()
+ public async Task Release()
{
CheckDisposed();
// we still don't want to dispose the dmb yet, even though we're keeping it alive
- var tmpProvider = reattachInformation.Dmb;
- reattachInformation.Dmb = null;
+ var tmpProvider = ReattachInformation.Dmb;
+ ReattachInformation.Dmb = null;
released = true;
await DisposeAsync().ConfigureAwait(false);
byondLock.DoNotDeleteThisSession();
tmpProvider.KeepAlive();
- reattachInformation.Dmb = tmpProvider;
- return reattachInformation;
+ ReattachInformation.Dmb = tmpProvider;
}
///
@@ -471,7 +470,7 @@ namespace Tgstation.Server.Host.Components.Session
return null;
}
- parameters.AccessIdentifier = reattachInformation.AccessIdentifier;
+ parameters.AccessIdentifier = ReattachInformation.AccessIdentifier;
var json = JsonConvert.SerializeObject(parameters, DMApiConstants.SerializerSettings);
logger.LogTrace("Topic request: {0}", json);
@@ -483,7 +482,7 @@ namespace Tgstation.Server.Host.Components.Session
byondTopicSender.SanitizeString(DMApiConstants.TopicData),
byondTopicSender.SanitizeString(json));
- var targetPort = reattachInformation.Port;
+ var targetPort = ReattachInformation.Port;
var topicResponse = await byondTopicSender.SendTopic(
new IPEndPoint(IPAddress.Loopback, targetPort),
@@ -547,7 +546,7 @@ namespace Tgstation.Server.Host.Components.Session
if (commandResult.InteropResponse?.ErrorMessage != null)
return false;
- reattachInformation.Port = port;
+ ReattachInformation.Port = port;
return true;
}
@@ -572,7 +571,7 @@ namespace Tgstation.Server.Host.Components.Session
logger.LogTrace("Changing reboot state to {0}", newRebootState);
- reattachInformation.RebootState = newRebootState;
+ ReattachInformation.RebootState = newRebootState;
var result = await SendCommand(
new TopicParameters(newRebootState),
cancellationToken)
@@ -586,7 +585,7 @@ namespace Tgstation.Server.Host.Components.Session
{
CheckDisposed();
logger.LogTrace("Resetting reboot state...");
- reattachInformation.RebootState = RebootState.Normal;
+ ReattachInformation.RebootState = RebootState.Normal;
}
///
@@ -601,15 +600,15 @@ namespace Tgstation.Server.Host.Components.Session
///
public void ReplaceDmbProvider(IDmbProvider dmbProvider)
{
- var oldDmb = reattachInformation.Dmb;
- reattachInformation.Dmb = dmbProvider ?? throw new ArgumentNullException(nameof(dmbProvider));
+ var oldDmb = ReattachInformation.Dmb;
+ ReattachInformation.Dmb = dmbProvider ?? throw new ArgumentNullException(nameof(dmbProvider));
oldDmb.Dispose();
}
///
public Task InstanceRenamed(string newInstanceName, CancellationToken cancellationToken)
{
- reattachInformation.RuntimeInformation.InstanceName = newInstanceName;
+ ReattachInformation.RuntimeInformation.InstanceName = newInstanceName;
return SendCommand(new TopicParameters(newInstanceName), cancellationToken);
}
@@ -667,7 +666,7 @@ namespace Tgstation.Server.Host.Components.Session
var reattachResponse = await SendCommand(
new TopicParameters(
assemblyInformationProvider.Version,
- reattachInformation.RuntimeInformation.ServerPort),
+ ReattachInformation.RuntimeInformation.ServerPort),
reattachTopicCts.Token)
.ConfigureAwait(false);
diff --git a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs
index c8cdcb5cd2..e5d8e415d5 100644
--- a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs
+++ b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs
@@ -72,12 +72,7 @@ namespace Tgstation.Server.Host.Components.Session
logger.LogDebug("Saving reattach information: {0}...", reattachInformation);
- await db
- .ReattachInformations
- .AsQueryable()
- .Where(x => x.CompileJob.Job.Instance.Id == metadata.Id)
- .DeleteAsync(cancellationToken)
- .ConfigureAwait(false);
+ await ClearImpl(db, false, cancellationToken).ConfigureAwait(false);
var dbReattachInfo = new Models.ReattachInformation
{
@@ -129,23 +124,25 @@ namespace Tgstation.Server.Host.Components.Session
bool first = true;
foreach (var reattachInfo in dbReattachInfos)
{
- if (!first)
+ if (first)
{
- logger.LogWarning("Killing PID {0} associated with extra reattach information...", reattachInfo.ProcessId);
- try
- {
- using var process = processExecutor.GetProcess(reattachInfo.ProcessId);
- process.Terminate();
- await process.Lifetime.ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- logger.LogWarning(ex, "Failed to kill process!");
- }
+ first = false;
+ continue;
+ }
+
+ logger.LogWarning("Killing PID {0} associated with extra reattach information...", reattachInfo.ProcessId);
+ try
+ {
+ using var process = processExecutor.GetProcess(reattachInfo.ProcessId);
+ process.Terminate();
+ await process.Lifetime.ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ logger.LogWarning(ex, "Failed to kill process!");
}
db.ReattachInformations.Remove(reattachInfo);
- first = false;
}
await db.Save(cancellationToken).ConfigureAwait(false);
@@ -173,5 +170,40 @@ namespace Tgstation.Server.Host.Components.Session
return info;
}
+
+ ///
+ public Task Clear(CancellationToken cancellationToken) => databaseContextFactory
+ .UseContext(
+ db =>
+ {
+ logger.LogDebug("Clearing reattach information");
+ return ClearImpl(db, true, cancellationToken);
+ });
+
+ ///
+ /// Clear any stored .
+ ///
+ /// The to use.
+ /// If an SQL DELETE WHERE command should be used rather than an Entity Framework transaction.
+ /// The for the operation.
+ /// A representing the running operation.
+ async Task ClearImpl(IDatabaseContext databaseContext, bool instant, CancellationToken cancellationToken)
+ {
+ var baseQuery = databaseContext
+ .ReattachInformations
+ .AsQueryable()
+ .Where(x => x.CompileJob.Job.Instance.Id == metadata.Id);
+
+ if (instant)
+ await baseQuery
+ .DeleteAsync(cancellationToken)
+ .ConfigureAwait(false);
+ else
+ {
+ var results = await baseQuery.ToListAsync(cancellationToken).ConfigureAwait(false);
+ foreach (var result in results)
+ databaseContext.ReattachInformations.Remove(result);
+ }
+ }
}
}
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs
index 6cc3fdac2d..ec41aa29f4 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs
@@ -199,7 +199,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
protected sealed override ISessionController GetActiveController() => Server;
///
- protected override async Task InitControllers(
+ protected override async Task InitController(
Task chatTask,
ReattachInformation reattachInfo,
CancellationToken cancellationToken)
@@ -249,6 +249,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
Server.SetHighPriority();
+ if (!reattachInProgress)
+ await SessionPersistor.Save(Server.ReattachInformation, cancellationToken).ConfigureAwait(false);
+
await CheckLaunchResult(Server, "Server", cancellationToken).ConfigureAwait(false);
Server.EnableCustomChatCommands();
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs
index b43c9ccdde..91b9bf82f8 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs
@@ -105,11 +105,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
}
///
- protected override async Task InitControllers(Task chatTask, ReattachInformation reattachInfo, CancellationToken cancellationToken)
+ protected override async Task InitController(Task chatTask, ReattachInformation reattachInfo, CancellationToken cancellationToken)
{
try
{
- await base.InitControllers(chatTask, reattachInfo, cancellationToken).ConfigureAwait(false);
+ await base.InitController(chatTask, reattachInfo, cancellationToken).ConfigureAwait(false);
}
finally
{
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
index 38f867557d..ad4db13d02 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
@@ -60,6 +60,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
protected TaskCompletionSource
readonly SemaphoreSlim controllerDisposeSemaphore;
- ///
- /// The for the .
- ///
- readonly ISessionPersistor sessionPersistor;
-
///
/// The for the .
///
@@ -135,11 +135,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
readonly bool autoStart;
- ///
- /// Used when detaching servers.
- ///
- ReattachInformation releasedReattachInformation;
-
///
/// The for the monitor loop.
///
@@ -176,7 +171,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// The value of .
/// The value of .
/// The value of .
- /// The value of .
+ /// The value of .
/// The value of .
/// The to populate with.
/// The value of .
@@ -206,7 +201,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
Chat = chat ?? throw new ArgumentNullException(nameof(chat));
SessionControllerFactory = sessionControllerFactory ?? throw new ArgumentNullException(nameof(sessionControllerFactory));
DmbFactory = dmbFactory ?? throw new ArgumentNullException(nameof(dmbFactory));
- this.sessionPersistor = sessionPersistor ?? throw new ArgumentNullException(nameof(sessionPersistor));
+ SessionPersistor = sessionPersistor ?? throw new ArgumentNullException(nameof(sessionPersistor));
this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
AsyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer));
this.diagnosticsIOManager = diagnosticsIOManager ?? throw new ArgumentNullException(nameof(diagnosticsIOManager));
@@ -347,7 +342,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
public async Task StartAsync(CancellationToken cancellationToken)
{
- var reattachInfo = await sessionPersistor.Load(cancellationToken).ConfigureAwait(false);
+ var reattachInfo = await SessionPersistor.Load(cancellationToken).ConfigureAwait(false);
if (!autoStart && reattachInfo == null)
return;
@@ -375,26 +370,8 @@ namespace Tgstation.Server.Host.Components.Watchdog
}
///
- public async Task StopAsync(CancellationToken cancellationToken)
- {
- await TerminateNoLock(false, !releaseServers, cancellationToken).ConfigureAwait(false);
- if (releasedReattachInformation != null)
- {
- try
- {
- await sessionPersistor.Save(releasedReattachInformation, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.LogCritical(
- ex,
- "Failed to persist session reattach information! To repair this, DreamDaemon will need to be manully stopped and then relaunched with TGS.");
- }
-
- releasedReattachInformation = null;
- releaseServers = false;
- }
- }
+ public Task StopAsync(CancellationToken cancellationToken) =>
+ TerminateNoLock(false, !releaseServers, cancellationToken);
///
public async Task Terminate(bool graceful, CancellationToken cancellationToken)
@@ -477,7 +454,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// to use, if any.
/// The for the operation.
/// A representing the running operation.
- protected abstract Task InitControllers(Task chatTask, ReattachInformation reattachInfo, CancellationToken cancellationToken);
+ protected abstract Task InitController(Task chatTask, ReattachInformation reattachInfo, CancellationToken cancellationToken);
///
/// Launches the watchdog.
@@ -525,11 +502,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
try
{
- await InitControllers(announceTask, reattachInfo, cancellationToken).ConfigureAwait(false);
+ await InitController(announceTask, reattachInfo, cancellationToken).ConfigureAwait(false);
}
- catch (OperationCanceledException)
+ catch (OperationCanceledException ex)
{
- Logger.LogTrace("Controller initialization canceled!");
+ Logger.LogTrace(ex, "Controller initialization cancelled!");
throw;
}
catch (Exception e)
@@ -610,7 +587,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
}
///
- /// Call from when a reattach operation fails to attempt a fresh start.
+ /// Call from when a reattach operation fails to attempt a fresh start.
///
/// The for the operation.
/// A representing the running operation.
@@ -623,7 +600,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
Logger.LogWarning(FailReattachMessage);
var chatTask = Chat.QueueWatchdogMessage(FailReattachMessage, cancellationToken);
- await InitControllers(chatTask, null, cancellationToken).ConfigureAwait(false);
+ await InitController(chatTask, null, cancellationToken).ConfigureAwait(false);
}
///
@@ -641,7 +618,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
{
Logger.LogTrace("DisposeAndNullControllers");
using (await SemaphoreSlimContext.Lock(controllerDisposeSemaphore, cancellationToken).ConfigureAwait(false))
+ {
await DisposeAndNullControllersImpl().ConfigureAwait(false);
+ if (!releaseServers)
+ await SessionPersistor.Clear(cancellationToken).ConfigureAwait(false);
+ }
}
///
@@ -931,8 +912,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
if (releaseServers)
{
- Logger.LogTrace("Detaching servers...");
- releasedReattachInformation = await GetActiveController().Release().ConfigureAwait(false);
+ Logger.LogTrace("Detaching server...");
+ var controller = GetActiveController();
+ await controller.Release().ConfigureAwait(false);
}
}