diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm
index fb6261a9bc..7ef3268322 100644
--- a/src/DMAPI/tgs.dm
+++ b/src/DMAPI/tgs.dm
@@ -95,10 +95,13 @@
#define TGS_EVENT_WATCHDOG_SHUTDOWN 15
/// Before the watchdog detaches for a TGS update/restart. No parameters.
#define TGS_EVENT_WATCHDOG_DETACH 16
-// We don't actually implement this value as the DMAPI can never receive it
+// We don't actually implement these 3 events as the DMAPI can never receive them.
// #define TGS_EVENT_WATCHDOG_LAUNCH 17
-// Same here. We don't actually implement this value as the DMAPI can never receive it
-// #define TGS_EVENT_WORLD_END_PROCESS 18
+// #define TGS_EVENT_WATCHDOG_CRASH 18
+// #define TGS_EVENT_WORLD_END_PROCESS 19
+// #define TGS_EVENT_WORLD_REBOOT 20
+/// Watchdog event when TgsInitializationComplete() is called. No parameters.
+ #define TGS_EVENT_WORLD_PRIME 21
// OTHER ENUMS
@@ -132,7 +135,6 @@
*
* This may use [/world/var/sleep_offline] to make this happen so ensure no changes are made to it while this call is running.
* Afterwards, consider explicitly setting it to what you want to avoid this BYOND bug: http://www.byond.com/forum/post/2575184
- * Before this point, note that any static files or directories may be in use by another server. Your code should account for this.
* This function should not be called before ..() in [/world/proc/New].
*/
/world/proc/TgsInitializationComplete()
diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs
index f22c1db8e0..dabb822de7 100644
--- a/src/Tgstation.Server.Host/Components/Events/EventType.cs
+++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs
@@ -96,7 +96,7 @@ namespace Tgstation.Server.Host.Components.Events
DeploymentComplete,
///
- /// Before the watchdog shutsdown. Not sent for graceful shutdowns. No parameters.
+ /// Before the watchdog shuts down. Not sent for graceful shutdowns. No parameters.
///
[EventScript("WatchdogShutdown")]
WatchdogShutdown,
@@ -114,9 +114,27 @@ namespace Tgstation.Server.Host.Components.Events
WatchdogLaunch,
///
- /// In between DD restarts if the process has been force-ended by the DMAPI (TgsEndProcess())
+ /// Watchdog event when DreamDaemon exits unexpectedly. No parameters.
+ ///
+ [EventScript("WatchdogCrash")]
+ WatchdogCrash,
+
+ ///
+ /// In between watchdog DreamDaemon restarts if the process has been force-ended by the DMAPI (TgsEndProcess()). No parameters.
///
[EventScript("WorldEndProcess")]
WorldEndProcess,
+
+ ///
+ /// Watchdog event when TgsReboot() is called. Not synchronous. Called after . No parameters.
+ ///
+ [EventScript("WorldReboot")]
+ WorldReboot,
+
+ ///
+ /// Watchdog event when TgsInitializationsComplete() is called. No parameters.
+ ///
+ [EventScript("WorldPrime")]
+ WorldPrime,
}
}
diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs
index 778c39ba38..9c7a43cb3a 100644
--- a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs
+++ b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs
@@ -49,12 +49,12 @@ namespace Tgstation.Server.Host.Components.Session
RebootState RebootState { get; }
///
- /// A that completes when the server calls /world/Reboot()
+ /// A that completes when the server calls /world/TgsReboot().
///
Task OnReboot { get; }
///
- /// A that completes when the server calls /world/TgsInitializationsComplete()
+ /// A that completes when the server calls /world/TgsInitializationComplete()
///
Task OnPrime { get; }
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs
index 433680a941..3cddd03a02 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs
@@ -92,10 +92,12 @@ namespace Tgstation.Server.Host.Components.Watchdog
switch (reason)
{
case MonitorActivationReason.ActiveServerCrashed:
- if (Server.TerminationWasRequested)
- await EventConsumer.HandleEvent(EventType.WorldEndProcess, Enumerable.Empty(), cancellationToken).ConfigureAwait(false);
+ var eventType = Server.TerminationWasRequested
+ ? EventType.WorldEndProcess
+ : EventType.WatchdogCrash;
+ await EventConsumer.HandleEvent(eventType, Enumerable.Empty(), cancellationToken).ConfigureAwait(false);
- string exitWord = Server.TerminationWasRequested ? "exited" : "crashed";
+ var exitWord = Server.TerminationWasRequested ? "exited" : "crashed";
if (Server.RebootState == Session.RebootState.Shutdown)
{
// the time for graceful shutdown is now
@@ -128,6 +130,8 @@ namespace Tgstation.Server.Host.Components.Watchdog
gracefulRebootRequired = false;
Server.ResetRebootState();
+ await EventConsumer.HandleEvent(EventType.WorldReboot, Enumerable.Empty(), cancellationToken).ConfigureAwait(false);
+
switch (rebootState)
{
case Session.RebootState.Normal:
@@ -144,7 +148,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
default:
throw new InvalidOperationException($"Invalid reboot state: {rebootState}");
}
-
case MonitorActivationReason.ActiveLaunchParametersUpdated:
await Server.SetRebootState(Session.RebootState.Restart, cancellationToken).ConfigureAwait(false);
gracefulRebootRequired = true;
@@ -152,6 +155,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
case MonitorActivationReason.NewDmbAvailable:
await HandleNewDmbAvailable(cancellationToken).ConfigureAwait(false);
break;
+ case MonitorActivationReason.ActiveServerPrimed:
+ await EventConsumer.HandleEvent(EventType.WorldPrime, Enumerable.Empty(), cancellationToken).ConfigureAwait(false);
+ break;
case MonitorActivationReason.Heartbeat:
default:
throw new InvalidOperationException($"Invalid activation reason: {reason}");
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/MonitorActivationReason.cs b/src/Tgstation.Server.Host/Components/Watchdog/MonitorActivationReason.cs
index 4b0d046561..4f1073e742 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/MonitorActivationReason.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/MonitorActivationReason.cs
@@ -1,4 +1,4 @@
-namespace Tgstation.Server.Host.Components.Watchdog
+namespace Tgstation.Server.Host.Components.Watchdog
{
///
/// Reasons for the monitor to wake up
@@ -29,5 +29,10 @@
/// A heartbeat is required.
///
Heartbeat,
+
+ ///
+ /// Server primed.
+ ///
+ ActiveServerPrimed,
}
}
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
index f6a7ed6160..3e89293cb3 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
@@ -609,6 +609,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
/// The for the operation.
/// A representing the running operation.
+ #pragma warning disable CA1502
private async Task MonitorLifetimes(CancellationToken cancellationToken)
{
Logger.LogTrace("Entered MonitorLifetimes");
@@ -619,6 +620,12 @@ namespace Tgstation.Server.Host.Components.Watchdog
try
{
MonitorAction nextAction = MonitorAction.Continue;
+ Task activeServerLifetime = null,
+ activeServerReboot = null,
+ serverPrimed = null,
+ activeLaunchParametersChanged = null,
+ newDmbAvailable = null;
+ ISessionController lastController = null;
for (ulong iteration = 1; nextAction != MonitorAction.Exit; ++iteration)
using (LogContext.PushProperty("Monitor", iteration))
try
@@ -627,17 +634,44 @@ namespace Tgstation.Server.Host.Components.Watchdog
nextAction = MonitorAction.Continue;
var controller = GetActiveController();
- Task activeServerLifetime = controller.Lifetime;
- var activeServerReboot = controller.OnReboot;
- Task activeLaunchParametersChanged = ActiveParametersUpdated.Task;
- var newDmbAvailable = DmbFactory.OnNewerDmb;
+ void UpdateMonitoredTasks()
+ {
+ static void TryUpdateTask(ref Task oldTask, Task newTask)
+ {
+ if (oldTask?.IsCompleted == true)
+ return;
+
+ oldTask = newTask;
+ }
+
+ if (lastController == controller)
+ {
+ TryUpdateTask(ref activeServerLifetime, controller.Lifetime);
+ TryUpdateTask(ref activeServerReboot, controller.OnReboot);
+ TryUpdateTask(ref serverPrimed, controller.OnPrime);
+ }
+ else
+ {
+ activeServerLifetime = controller.Lifetime;
+ activeServerReboot = controller.OnReboot;
+ serverPrimed = controller.OnPrime;
+ lastController = controller;
+ }
+
+ TryUpdateTask(ref activeLaunchParametersChanged, ActiveParametersUpdated.Task);
+ TryUpdateTask(ref newDmbAvailable, DmbFactory.OnNewerDmb);
+ }
+
+ UpdateMonitoredTasks();
var heartbeatSeconds = ActiveLaunchParameters.HeartbeatSeconds.Value;
var heartbeat = heartbeatSeconds == 0
|| !controller.DMApiAvailable
? Extensions.TaskExtensions.InfiniteTask()
- : Task.Delay(TimeSpan.FromSeconds(heartbeatSeconds), cancellationToken);
+ : Task.Delay(
+ TimeSpan.FromSeconds(heartbeatSeconds),
+ cancellationToken);
// cancel waiting if requested
var cancelTcs = new TaskCompletionSource