mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-24 05:27:30 +01:00
+6
-4
@@ -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()
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace Tgstation.Server.Host.Components.Events
|
||||
DeploymentComplete,
|
||||
|
||||
/// <summary>
|
||||
/// Before the watchdog shutsdown. Not sent for graceful shutdowns. No parameters.
|
||||
/// Before the watchdog shuts down. Not sent for graceful shutdowns. No parameters.
|
||||
/// </summary>
|
||||
[EventScript("WatchdogShutdown")]
|
||||
WatchdogShutdown,
|
||||
@@ -114,9 +114,27 @@ namespace Tgstation.Server.Host.Components.Events
|
||||
WatchdogLaunch,
|
||||
|
||||
/// <summary>
|
||||
/// In between DD restarts if the process has been force-ended by the DMAPI (TgsEndProcess())
|
||||
/// Watchdog event when DreamDaemon exits unexpectedly. No parameters.
|
||||
/// </summary>
|
||||
[EventScript("WatchdogCrash")]
|
||||
WatchdogCrash,
|
||||
|
||||
/// <summary>
|
||||
/// In between watchdog DreamDaemon restarts if the process has been force-ended by the DMAPI (TgsEndProcess()). No parameters.
|
||||
/// </summary>
|
||||
[EventScript("WorldEndProcess")]
|
||||
WorldEndProcess,
|
||||
|
||||
/// <summary>
|
||||
/// Watchdog event when TgsReboot() is called. Not synchronous. Called after <see cref="WorldEndProcess"/>. No parameters.
|
||||
/// </summary>
|
||||
[EventScript("WorldReboot")]
|
||||
WorldReboot,
|
||||
|
||||
/// <summary>
|
||||
/// Watchdog event when TgsInitializationsComplete() is called. No parameters.
|
||||
/// </summary>
|
||||
[EventScript("WorldPrime")]
|
||||
WorldPrime,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,12 +49,12 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
RebootState RebootState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="Task"/> that completes when the server calls /world/Reboot()
|
||||
/// A <see cref="Task"/> that completes when the server calls /world/TgsReboot().
|
||||
/// </summary>
|
||||
Task OnReboot { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="Task"/> that completes when the server calls /world/TgsInitializationsComplete()
|
||||
/// A <see cref="Task"/> that completes when the server calls /world/TgsInitializationComplete()
|
||||
/// </summary>
|
||||
Task OnPrime { get; }
|
||||
|
||||
|
||||
@@ -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<string>(), cancellationToken).ConfigureAwait(false);
|
||||
var eventType = Server.TerminationWasRequested
|
||||
? EventType.WorldEndProcess
|
||||
: EventType.WatchdogCrash;
|
||||
await EventConsumer.HandleEvent(eventType, Enumerable.Empty<string>(), 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<string>(), 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<string>(), cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
case MonitorActivationReason.Heartbeat:
|
||||
default:
|
||||
throw new InvalidOperationException($"Invalid activation reason: {reason}");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Tgstation.Server.Host.Components.Watchdog
|
||||
namespace Tgstation.Server.Host.Components.Watchdog
|
||||
{
|
||||
/// <summary>
|
||||
/// Reasons for the monitor to wake up
|
||||
@@ -29,5 +29,10 @@
|
||||
/// A heartbeat is required.
|
||||
/// </summary>
|
||||
Heartbeat,
|
||||
|
||||
/// <summary>
|
||||
/// Server primed.
|
||||
/// </summary>
|
||||
ActiveServerPrimed,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,6 +609,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
#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<object>();
|
||||
@@ -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
|
||||
|
||||
/// <summary>
|
||||
/// Starts all <see cref="ISessionController"/>s.
|
||||
|
||||
@@ -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}"
|
||||
|
||||
Reference in New Issue
Block a user