2using System.Globalization;
4using System.Threading.Tasks;
6using Microsoft.Extensions.Hosting;
7using Microsoft.Extensions.Logging;
44 readonly ILogger<SystemDManager>
logger;
69 ILogger<SystemDManager>
logger)
74 ArgumentNullException.ThrowIfNull(serverControl);
76 this.logger =
logger ??
throw new ArgumentNullException(nameof(
logger));
89 public ValueTask
HandleRestart(Version? updateVersion,
bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken)
93 return ValueTask.CompletedTask;
97 protected override async Task
ExecuteAsync(CancellationToken cancellationToken)
101 logger.LogDebug(
"SystemD not detected");
105 logger.LogDebug(
"SystemD detected");
108 throw new InvalidOperationException(
"RunAsync called after application started!");
110 logger.LogTrace(
"Installing lifetime handlers...");
115 if (Interlocked.Increment(ref readyCounts) < 2)
125 ? $
"RELOADING=1\nMONOTONIC_USEC={GetMonotonicUsec()}"
133 var watchdogUsec = Environment.GetEnvironmentVariable(
"WATCHDOG_USEC");
134 if (String.IsNullOrWhiteSpace(watchdogUsec))
136 logger.LogDebug(
"WATCHDOG_USEC not present, not starting watchdog loop");
140 var microseconds = UInt64.Parse(watchdogUsec, CultureInfo.InvariantCulture);
141 var timeoutIntervalMillis = (int)(microseconds / 1000);
143 logger.LogDebug(
"Starting watchdog loop with interval of {timeoutInterval}ms", timeoutIntervalMillis);
145 var timeoutInterval = TimeSpan.FromMilliseconds(timeoutIntervalMillis);
146 var nextExpectedTimeout = DateTimeOffset.UtcNow + timeoutInterval;
147 var timeToNextExpectedTimeout = nextExpectedTimeout - DateTimeOffset.UtcNow;
148 while (!cancellationToken.IsCancellationRequested)
150 var delayInterval = timeToNextExpectedTimeout / 2;
151 await Task.Delay(delayInterval, cancellationToken);
155 var now = DateTimeOffset.UtcNow;
157 nextExpectedTimeout = now + timeoutInterval;
159 timeToNextExpectedTimeout = nextExpectedTimeout - now;
162 logger.LogWarning(
"Missed systemd heartbeat! Expected timeout in {timeoutMs}ms...", timeToNextExpectedTimeout.TotalMilliseconds);
165 catch (OperationCanceledException ex)
167 logger.LogTrace(ex,
"Watchdog loop cancelled!");
171 logger.LogError(ex,
"Watchdog loop crashed!");
174 logger.LogDebug(
"Exited watchdog loop");
184 logger.LogTrace(
"Sending sd_notify {message}...", command);
192 logger.LogInformation(ex,
"Exception attempting to invoke sd_notify!");
200 logger.LogError(
new UnixIOException(result),
"sd_notify {message} failed!", command);
202 logger.LogTrace(
"Could not send sd_notify {message}. Socket closed!", command);
Native 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.
readonly IRestartRegistration restartRegistration
The IRestartRegistration for the SystemDManager.
override async Task ExecuteAsync(CancellationToken cancellationToken)
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.
ValueTask HandleRestart(Version? updateVersion, bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken)
Handle a restart of the server.A ValueTask representing the running operation.
const string SDNotifyWatchdog
The sd_notify command for notifying the watchdog we are alive.
bool restartInProgress
If TGS is going to restart.
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.