Files
mxaccessgw/src/MxGateway.Server/Workers/OrphanWorkerCleanupHostedService.cs
T
Joseph Doherty 1d9e3afadd Resolve Server-002, -004, -005, -006 code-review findings
Server-002: the gateway never terminated leftover MxGateway.Worker.exe
processes at startup, contradicting gateway.md and CLAUDE.md. Added
IRunningProcessInspector/SystemRunningProcessInspector, OrphanWorkerTerminator,
and OrphanWorkerCleanupHostedService (best-effort, runs before sessions are
accepted); updated gateway.md to describe the implemented behavior.

Server-004: API-key scopes were persisted verbatim with no validation. Added
GatewayScopes.All/IsKnown; the CLI parser and dashboard create path now
reject unknown scope strings.

Server-005: a non-SqlException/InvalidOperationException fault on the initial
Galaxy hierarchy load faulted the BackgroundService. ExecuteAsync now catches
all non-cancellation exceptions on first load and RefreshCoreAsync broadens
its catch so the cache records Stale/Unavailable instead.

Server-006: OpenSessionAsync incremented the open-sessions gauge before
alarm auto-subscribe; an auto-subscribe failure leaked the gauge. The catch
path now calls SessionRemoved() when the gauge was incremented.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 21:31:10 -04:00

31 lines
968 B
C#

namespace MxGateway.Server.Workers;
/// <summary>
/// Hosted service that terminates leftover MXAccess worker processes once on
/// gateway startup, before the server begins accepting sessions.
/// </summary>
public sealed class OrphanWorkerCleanupHostedService(
OrphanWorkerTerminator terminator,
ILogger<OrphanWorkerCleanupHostedService> logger) : IHostedService
{
/// <inheritdoc />
public Task StartAsync(CancellationToken cancellationToken)
{
try
{
terminator.TerminateOrphans();
}
catch (Exception exception)
{
// Orphan cleanup is best-effort; a failure here must not prevent
// the gateway from starting.
logger.LogWarning(exception, "Orphan worker cleanup failed on startup.");
}
return Task.CompletedTask;
}
/// <inheritdoc />
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}