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(); @@ -647,7 +681,8 @@ namespace Tgstation.Server.Host.Components.Watchdog heartbeat, newDmbAvailable, cancelTcs.Task, - activeLaunchParametersChanged); + activeLaunchParametersChanged, + serverPrimed); // wait for something to happen using (cancellationToken.Register(() => cancelTcs.SetCanceled())) @@ -688,7 +723,10 @@ namespace Tgstation.Server.Host.Components.Watchdog || CheckActivationReason(ref activeServerReboot, MonitorActivationReason.ActiveServerRebooted) || CheckActivationReason(ref newDmbAvailable, MonitorActivationReason.NewDmbAvailable) || CheckActivationReason(ref activeLaunchParametersChanged, MonitorActivationReason.ActiveLaunchParametersUpdated) - || CheckActivationReason(ref heartbeat, MonitorActivationReason.Heartbeat); + || CheckActivationReason(ref heartbeat, MonitorActivationReason.Heartbeat) + || CheckActivationReason(ref serverPrimed, MonitorActivationReason.ActiveServerPrimed); + + UpdateMonitoredTasks(); if (!anyActivation) moreActivationsToProcess = false; @@ -769,6 +807,7 @@ namespace Tgstation.Server.Host.Components.Watchdog Logger.LogTrace("Monitor exiting..."); } + #pragma warning restore CA1502 /// /// Starts all s. diff --git a/tgstation-server.sln b/tgstation-server.sln index 7e771b4b01..32dabe36ba 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -65,6 +65,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tgs", "tgs", "{F7765A4B-021 src\DMAPI\tgs\includes.dm = src\DMAPI\tgs\includes.dm src\DMAPI\tgs\LICENSE = src\DMAPI\tgs\LICENSE src\DMAPI\tgs\README.md = src\DMAPI\tgs\README.md + src\DMAPI\tgs.dm = src\DMAPI\tgs.dm EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "core", "core", "{DCCBA9DA-47BA-4C70-823B-E99A3ACA0377}"