2using System.Collections.Generic;
6using System.Threading.Tasks;
8using Microsoft.Extensions.DependencyInjection;
9using Microsoft.Extensions.Hosting;
10using Microsoft.Extensions.Logging;
11using Microsoft.Extensions.Options;
29#if WATCHDOG_FREE_RESTART
38 internal IHost Host {
get;
private set; }
112 public async Task
Run(CancellationToken cancellationToken)
115 using (var fsWatcher =
updatePath !=
null ?
new FileSystemWatcher(Path.GetDirectoryName(
updatePath)) :
null)
117 if (fsWatcher !=
null)
120 fsWatcher.EnableRaisingEvents =
true;
129 logger = Host.Services.GetRequiredService<ILogger<Server>>();
130 using (cancellationToken.Register(() =>
logger.LogInformation(
"Server termination requested!")))
132 var generalConfigurationOptions = Host.Services.GetRequiredService<IOptions<GeneralConfiguration>>();
140 catch (OperationCanceledException ex)
142 logger.LogDebug(ex,
"Server run cancelled!");
167 ArgumentNullException.ThrowIfNull(updateExecutor);
168 ArgumentNullException.ThrowIfNull(newVersion);
172 logger.LogTrace(
"Begin ApplyUpdate...");
174 CancellationToken criticalCancellationToken;
179 logger.LogDebug(
"Aborted update due to concurrency conflict!");
184 throw new InvalidOperationException(
"Tried to update a non-running Server!");
190 async Task RunUpdate()
194 logger.LogTrace(
"Update complete!");
199 logger.LogTrace(
"Stopping host due to termination request...");
204 logger.LogTrace(
"Update failed!");
216 ArgumentNullException.ThrowIfNull(handler);
223 logger.LogTrace(
"Registering restart handler {handlerImplementationName}...", handler);
233 logger.LogWarning(
"Restart handler {handlerImplementationName} register after a shutdown had begun!", handler);
244 public Task
Die(Exception exception) =>
RestartImpl(
null, exception,
false,
true);
253 throw new InvalidOperationException(
"Server restarts are not supported");
256 throw new InvalidOperationException(
"Tried to control a non-running Server!");
268 if (otherException !=
null)
282 async Task
RestartImpl(Version newVersion, Exception exception,
bool requireWatchdog,
bool completeAsap)
287 bool isGracefulShutdown = !requireWatchdog && exception ==
null;
289 "Begin {restartType}...",
292 ?
"semi-graceful shutdown"
293 :
"graceful shutdown"
300 logger.LogTrace(
"Aborted restart due to concurrency conflict!");
308 if (exception ==
null)
310 var giveHandlersTimeToWaitAround = isGracefulShutdown && !completeAsap;
311 logger.LogInformation(
"Stopping server...");
312 using var cts =
new CancellationTokenSource(
313 TimeSpan.FromMinutes(
314 giveHandlersTimeToWaitAround
317 var cancellationToken = cts.Token;
320 var eventsTask = Task.WhenAll(
322 x => x.HandleRestart(newVersion, giveHandlersTimeToWaitAround, cancellationToken))
325 logger.LogTrace(
"Joining restart handlers...");
328 catch (OperationCanceledException ex)
330 if (isGracefulShutdown)
331 logger.LogWarning(ex,
"Graceful shutdown timeout hit! Existing DreamDaemon processes will be terminated!");
335 "Restart timeout hit! Existing DreamDaemon processes will be lost and must be killed manually before being restarted with TGS!");
339 logger.LogError(e,
"Restart handlers error!");
353 logger?.LogTrace(
"FileSystemWatcher triggered.");
356 if (eventArgs.FullPath == Path.GetFullPath(
updatePath) && File.Exists(eventArgs.FullPath))
358 logger?.LogInformation(
"Host watchdog appears to be requesting server termination!");
370 logger?.LogInformation(
"An update is in progress, we will wait for that to complete...");
380 logger.LogTrace(
"Stopping host...");
General configuration options.
uint ShutdownTimeoutMinutes
The timeout minutes for gracefully stopping the server.
uint RestartTimeoutMinutes
The timeout minutes for restarting the server.
bool WatchdogPresent
true if live updates are supported, false. TryStartUpdate(IServerUpdateExecutor, Version) and Restart...
Task updateTask
The Task that is used for asynchronously updating the server.
IRestartRegistration RegisterForRestart(IRestartHandler handler)
Register a given handler to run before stopping the server for a restart. A new IRestartRegistration...
bool UpdateInProgress
Whether or not the server is currently updating.
bool TryStartUpdate(IServerUpdateExecutor updateExecutor, Version newVersion)
Attempt to update with a given updateExecutor . true if the update started successfully,...
GeneralConfiguration generalConfiguration
The GeneralConfiguration for the Server.
readonly string updatePath
The absolute path to install updates to.
void CheckSanity(bool checkWatchdog)
Throws an InvalidOperationException if the IServerControl cannot be used.
async Task Run(CancellationToken cancellationToken)
Runs the IServer. A Task representing the running operation.
Exception propagatedException
The Exception to propagate when the server terminates.
readonly List< IRestartHandler > restartHandlers
The IRestartHandlers to run when the Server restarts.
CancellationTokenSource cancellationTokenSource
The cancellationTokenSource for the Server.
async Task RestartImpl(Version newVersion, Exception exception, bool requireWatchdog, bool completeAsap)
Implements Restart().
bool terminateIfUpdateFails
If there is an update in progress and this flag is set, it should stop the server immediately if it f...
void WatchForShutdownFileCreation(object sender, FileSystemEventArgs eventArgs)
Event handler for the updatePath's FileSystemWatcher. Triggers shutdown if requested by host watchdog...
Task Restart()
Restarts the Host. A Task representing the running operation.
readonly IHostBuilder hostBuilder
The IHostBuilder for the Server.
void CheckExceptionPropagation(Exception otherException)
Re-throw propagatedException if it exists.
readonly object restartLock
lock object for certain restart related operations.
bool shutdownInProgress
If the server is being shut down or restarted.
Task GracefulShutdown(bool detach)
Gracefully shutsdown the Host. A Task representing the running operation.
bool RestartRequested
If the IServer should restart.
Task Die(Exception exception)
Kill the server with a fatal exception. A Task representing the running operation.
ILogger< Server > logger
The ILogger for the Server.
Server(IHostBuilder hostBuilder, string updatePath)
Initializes a new instance of the Server class.
void StopServerImmediate()
Fires off the cancellationTokenSource without any checks, shutting down everything.
Handler for server restarts.
Represents the lifetime of a IRestartHandler registration.
Represents a service that may take an updated Host assembly and run it, stopping the current assembly...
Executes server update operations.
Task< bool > ExecuteUpdate(string updatePath, CancellationToken cancellationToken, CancellationToken criticalCancellationToken)
Executes a pending server update by extracting the new server to a given updatePath .