1 using Microsoft.Extensions.Logging;
3 using System.Collections.Generic;
6 using System.Threading.Tasks;
23 public sealed
override bool AlphaIsActive =>
true;
26 public sealed
override Models.CompileJob ActiveCompileJob =>
Server?.Dmb.CompileJob;
65 ILogger<BasicWatchdog> logger,
67 Api.Models.Instance instance,
71 sessionControllerFactory,
74 databaseContextFactory,
79 initialLaunchParameters,
92 return new Dictionary<MonitorActivationReason, Task>
108 string exitWord =
Server.TerminationWasRequested ?
"exited" :
"crashed";
109 if (
Server.RebootState == Session.RebootState.Shutdown)
112 await Chat.SendWatchdogMessage(
114 CultureInfo.InvariantCulture,
115 "Server {0}! Shutting down due to graceful termination request...",
119 .ConfigureAwait(
false);
124 await Chat.SendWatchdogMessage(
126 CultureInfo.InvariantCulture,
127 "Server {0}! Rebooting...",
131 .ConfigureAwait(
false);
137 var rebootState =
Server.RebootState;
138 if (gracefulRebootRequired && rebootState == Session.RebootState.Normal)
140 Logger.LogError(
"Watchdog reached normal reboot state with gracefulRebootRequired set!");
141 rebootState = Session.RebootState.
Restart;
144 gracefulRebootRequired =
false;
145 Server.ResetRebootState();
149 case Session.RebootState.Normal:
150 monitorState.
NextAction = HandleNormalReboot();
152 case Session.RebootState.Restart:
155 case Session.RebootState.Shutdown:
157 await Chat.SendWatchdogMessage(
158 "Active server rebooted! Shutting down due to graceful termination request...",
161 .ConfigureAwait(
false);
165 throw new InvalidOperationException($
"Invalid reboot state: {rebootState}");
170 await
Server.SetRebootState(Session.RebootState.Restart, cancellationToken).ConfigureAwait(
false);
171 gracefulRebootRequired =
true;
174 await HandleNewDmbAvailable(cancellationToken).ConfigureAwait(
false);
179 throw new NotSupportedException($
"Unsupported activation reason: {reason}");
182 throw new InvalidOperationException($
"Invalid activation reason: {reason}");
190 AlphaIsActive =
true,
200 gracefulRebootRequired =
false;
209 var serverToReattach = reattachInfo?.
Alpha ?? reattachInfo?.
Bravo;
210 var serverToKill = reattachInfo?.
Bravo ?? reattachInfo?.
Alpha;
213 if (serverToKill == serverToReattach)
216 if (reattachInfo?.AlphaIsActive ==
false)
218 var temp = serverToReattach;
219 serverToReattach = serverToKill;
224 var doesntNeedNewDmb = serverToReattach != null;
228 bool inactiveServerWasKilled =
false;
234 Task<ISessionController> serverLaunchTask, inactiveReattachTask;
235 if (!doesntNeedNewDmb)
237 dmbToUse = await PrepServerForLaunch(dmbToUse, cancellationToken).ConfigureAwait(
false);
241 ActiveLaunchParameters,
250 bool thereIsAnInactiveServerToKill = serverToKill != null;
251 if (thereIsAnInactiveServerToKill)
257 Server = await serverLaunchTask.ConfigureAwait(
false);
262 var inactiveServerController = await inactiveReattachTask.ConfigureAwait(
false);
263 inactiveServerController?.Dispose();
264 inactiveServerWasKilled = inactiveServerController != null;
270 await NotifyOfFailedReattach(thereIsAnInactiveServerToKill && !inactiveServerWasKilled, cancellationToken).ConfigureAwait(
false);
274 await CheckLaunchResult(Server,
"Server", cancellationToken).ConfigureAwait(
false);
281 bool serverWasActive =
Server != null;
282 DisposeAndNullControllers();
285 if (dmbToUse != null && !serverWasActive)
288 if (serverToKill != null && !inactiveServerWasKilled)
289 serverToKill.Dmb.Dispose();
300 bool dmbUpdatePending = ActiveLaunchParameters != LastLaunchParameters;
311 gracefulRebootRequired =
true;
312 return Server.SetRebootState(Session.RebootState.Restart, cancellationToken);
321 protected virtual Task<IDmbProvider> PrepServerForLaunch(
IDmbProvider dmbToUse, CancellationToken cancellationToken) => Task.FromResult(dmbToUse);
326 if (!gracefulRebootRequired)
327 return base.ResetRebootState(cancellationToken);
329 return Restart(
true, cancellationToken);
341 DisposeAndNullControllers();
342 const string FailReattachMessage =
"Unable to properly reattach to server! Restarting...";
343 Logger.LogWarning(FailReattachMessage);
344 Logger.LogDebug(inactiveReattachSuccess ?
"Also could not reattach to inactive server!" :
"Inactive server was reattached successfully!");
345 Task chatTask = Chat.SendWatchdogMessage(FailReattachMessage,
false, cancellationToken);
346 await LaunchNoLock(
true,
false, null, cancellationToken).ConfigureAwait(
false);
347 await chatTask.ConfigureAwait(
false);
351 public sealed
override Task InstanceRenamed(
string newInstanceName, CancellationToken cancellationToken)
352 =>
Server?.InstanceRenamed(newInstanceName, cancellationToken) ?? Task.CompletedTask;
BasicWatchdog(IChatManager chat, ISessionControllerFactory sessionControllerFactory, IDmbFactory dmbFactory, IReattachInfoHandler reattachInfoHandler, IDatabaseContextFactory databaseContextFactory, IJobManager jobManager, IServerControl serverControl, IAsyncDelayer asyncDelayer, ILogger< BasicWatchdog > logger, DreamDaemonLaunchParameters initialLaunchParameters, Api.Models.Instance instance, bool autoStart)
Initializes a new instance of the BasicWatchdog .
async Task< ISessionController > Reattach(ReattachInformation reattachInformation, CancellationToken cancellationToken)
Create a ISessionController from an existing DreamDaemon instance
void EnableCustomChatCommands()
Enables the reading of custom chat commands from the ISessionController
bool gracefulRebootRequired
If the server is set to gracefully reboot due to a pending dmb or settings change.
Base class for IWatchdogs.
MonitorAction NextAction
The next MonitorAction to take in WatchdogBase.MonitorLifetimes(global::System.Threading.CancellationToken)
async Task< ISessionController > LaunchNew(IDmbProvider dmbProvider, IByondExecutableLock currentByondLock, DreamDaemonLaunchParameters launchParameters, bool primaryPort, bool primaryDirectory, bool apiValidate, CancellationToken cancellationToken)
Create a ISessionController from a freshly launch DreamDaemon instance
Factory for scoping usage of IDatabaseContexts. Meant for use by Components
virtual Task HandleNewDmbAvailable(CancellationToken cancellationToken)
Handler for MonitorActivationReason.NewDmbAvailable.
Launch settings for DreamDaemon
virtual MonitorAction HandleNormalReboot()
Handler for MonitorActivationReason.ActiveServerRebooted when the RebootState is RebootState.Normal.
For waiting asynchronously
override void DisposeAndNullControllersImpl()
Call IDisposable.Dispose and null the fields for all ISessionControllers and set Running to ...
For managing connected chat services
RebootState
Represents the action to take when /world/Reboot() is called
A IWatchdog that manages one server.
Factory for ISessionControllers
MonitorActivationReason
Reasons for the monitor to wake up
ISessionController ActiveServer
The active ISessionController
Factory for IDmbProviders
override async Task HandleMonitorWakeup(MonitorActivationReason reason, MonitorState monitorState, CancellationToken cancellationToken)
Handles the actions to take when the monitor has to "wake up"
Task Restart()
Restarts the Host
void SetHighPriority()
Set's the owned global::System.Diagnostics.Process.PriorityClass to global::System.Diagnostics.ProcessPriorityClass.AboveNormal
override IReadOnlyDictionary< MonitorActivationReason, Task > GetMonitoredServerTasks(MonitorState monitorState)
Gets the tasks for the following MonitorActivationReasons: MonitorActivationReason.ActiveServerCrashed, MonitorActivationReason.ActiveServerRebooted, MonitorActivationReason.InactiveServerCrashed, MonitorActivationReason.InactiveServerRebooted, MonitorActivationReason.InactiveServerStartupComplete.
Handles communication with a DreamDaemon IProcess
Manages the runtime of Jobs
Provides absolute paths to the latest compiled .dmbs
Handles saving and loading DualReattachInformation
sealed override async Task InitControllers(Action callBeforeRecurse, Task chatTask, DualReattachInformation reattachInfo, CancellationToken cancellationToken)
Starts all ISessionControllers.
MonitorAction
The action for the monitor loop to take when control is returned to it
override Task ResetRebootState(CancellationToken cancellationToken)
Cancels pending graceful actions
IDmbProvider LockNextDmb(int lockCount)
Gets the next IDmbProvider
The (absolute) state of the ExperimentalWatchdog
Represents a service that may take an updated Host assembly and run it, stopping the current assembly...
async Task NotifyOfFailedReattach(bool inactiveReattachSuccess, CancellationToken cancellationToken)
Send a chat message and log about a failed reattach operation and attempts another call to WatchdogBa...