2using System.Globalization;
4using System.Threading.Tasks;
6using Microsoft.Extensions.Hosting;
7using Microsoft.Extensions.Logging;
45 readonly ILogger<SystemDManager>
logger;
80 ILogger<SystemDManager>
logger)
85 ArgumentNullException.ThrowIfNull(serverControl);
87 this.logger =
logger ??
throw new ArgumentNullException(nameof(
logger));
109 public Task
HandleRestart(Version updateVersion,
bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken)
113 return Task.CompletedTask;
121 logger.LogDebug(
"SystemD detected");
126 logger.LogDebug(
"SystemD not detected");
130 return Task.CompletedTask;
134 public async Task
StopAsync(CancellationToken cancellationToken)
137 await
runTask.WithToken(cancellationToken);
145 async Task
RunAsync(CancellationToken cancellationToken)
148 throw new InvalidOperationException(
"RunAsync called after application started!");
150 logger.LogTrace(
"Installing lifetime handlers...");
155 if (Interlocked.Increment(ref readyCounts) < 2)
165 ? $
"RELOADING=1\nMONOTONIC_USEC={GetMonotonicUsec()}"
173 var watchdogUsec = Environment.GetEnvironmentVariable(
"WATCHDOG_USEC");
174 if (String.IsNullOrWhiteSpace(watchdogUsec))
176 logger.LogDebug(
"WATCHDOG_USEC not present, not starting watchdog loop");
180 var microseconds = UInt64.Parse(watchdogUsec, CultureInfo.InvariantCulture);
181 var timeoutIntervalMillis = (int)(microseconds / 1000);
183 logger.LogDebug(
"Starting watchdog loop with interval of {timeoutInterval}ms", timeoutIntervalMillis);
185 var timeoutInterval = TimeSpan.FromMilliseconds(timeoutIntervalMillis);
186 var nextExpectedTimeout = DateTimeOffset.UtcNow + timeoutInterval;
187 var timeToNextExpectedTimeout = nextExpectedTimeout - DateTimeOffset.UtcNow;
188 while (!cancellationToken.IsCancellationRequested)
190 var delayInterval = timeToNextExpectedTimeout / 2;
191 await Task.Delay(delayInterval, cancellationToken);
195 var now = DateTimeOffset.UtcNow;
197 nextExpectedTimeout = now + timeoutInterval;
199 timeToNextExpectedTimeout = nextExpectedTimeout - now;
202 logger.LogWarning(
"Missed systemd heartbeat! Expected timeout in {timeoutMs}ms...", timeToNextExpectedTimeout.TotalMilliseconds);
205 catch (OperationCanceledException ex)
207 logger.LogTrace(ex,
"Watchdog loop cancelled!");
211 logger.LogError(ex,
"Watchdog loop crashed!");
214 logger.LogDebug(
"Exited watchdog loop");
224 logger.LogTrace(
"Sending sd_notify {message}...", command);
232 logger.LogInformation(ex,
"Exception attempting to invoke sd_notify!");
240 logger.LogError(
new UnixIOException(result),
"sd_notify READY=1 failed!");
242 logger.LogTrace(
"Could not send sd_notify {message}. Socket closed!", command);
Native Windows methods used by the code.
static int sd_notify(int unset_environment, [MarshalAs(UnmanagedType.LPUTF8Str)] string state)
See https://www.freedesktop.org/software/systemd/man/sd_notify.html.
Implements the SystemD notify service protocol.
Task runTask
The main task executing in the SystemDManager.
Task StartAsync(CancellationToken cancellationToken)
readonly IRestartRegistration restartRegistration
The IRestartRegistration for the SystemDManager.
async Task StopAsync(CancellationToken cancellationToken)
Task HandleRestart(Version updateVersion, bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken)
Handle a restart of the server. A Task representing the running operation.
static long GetMonotonicUsec()
Get the current total nanoseconds value of the CLOCK_MONOTONIC clock.
readonly ILogger< SystemDManager > logger
The ILogger for the SystemDManager.
SystemDManager(IHostApplicationLifetime applicationLifetime, IInstanceManager instanceManager, IServerControl serverControl, ILogger< SystemDManager > logger)
Initializes a new instance of the SystemDManager class.
const string SDNotifyWatchdog
The sd_notify command for notifying the watchdog we are alive.
bool restartInProgress
If TGS is going to restart.
readonly CancellationTokenSource watchdogCts
The CancellationTokenSource for runTask.
async Task RunAsync(CancellationToken cancellationToken)
Runs the SystemDManager.
readonly IHostApplicationLifetime applicationLifetime
The IHostApplicationLifetime for the SystemDManager.
bool SendSDNotify(string command)
Send a sd_notify command .
readonly IInstanceManager instanceManager
The IInstanceManager for the SystemDManager.
Task Ready
Task that completes when the IInstanceManager finishes initializing.
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...
IRestartRegistration RegisterForRestart(IRestartHandler handler)
Register a given handler to run before stopping the server for a restart.