docs(src): add missing XML docs and strip tracking-ID comments

Sweep of 203 source files resolving CommentChecker findings: add
<summary>/<param>/<returns>/<inheritdoc> where missing, and remove
resolved task/issue tracking markers (Tests-NNN, Worker-NNN, Server-NNN,
Task N) from code comments. Comment/doc-only — no logic changes.
Server+Tests build clean under TreatWarningsAsErrors.
This commit is contained in:
Joseph Doherty
2026-07-07 14:09:49 -04:00
parent 8914472706
commit fca978de07
203 changed files with 1834 additions and 1383 deletions
@@ -19,12 +19,14 @@ public interface IWorkerClient : IAsyncDisposable
/// <summary>Initiates the handshake and enters ready state.</summary>
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
Task StartAsync(CancellationToken cancellationToken);
/// <summary>Sends a command to the worker and waits for a reply.</summary>
/// <param name="command">Worker command to invoke.</param>
/// <param name="timeout">Timeout for waiting for the reply.</param>
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
/// <returns>The worker's reply to the command.</returns>
Task<WorkerCommandReply> InvokeAsync(
WorkerCommand command,
TimeSpan timeout,
@@ -32,11 +34,13 @@ public interface IWorkerClient : IAsyncDisposable
/// <summary>Reads events from the worker as they arrive.</summary>
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
/// <returns>An asynchronous stream of worker events.</returns>
IAsyncEnumerable<WorkerEvent> ReadEventsAsync(CancellationToken cancellationToken);
/// <summary>Gracefully shuts down the worker by closing the connection.</summary>
/// <param name="timeout">Timeout for shutdown.</param>
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
Task ShutdownAsync(TimeSpan timeout, CancellationToken cancellationToken);
/// <summary>Terminates the worker process immediately with a diagnostic reason.</summary>
@@ -24,6 +24,7 @@ public interface IWorkerProcess : IDisposable
/// Waits for the process to exit with the specified cancellation token.
/// </summary>
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
ValueTask WaitForExitAsync(CancellationToken cancellationToken);
/// <summary>
@@ -8,7 +8,9 @@ public sealed class OrphanWorkerCleanupHostedService(
OrphanWorkerTerminator terminator,
ILogger<OrphanWorkerCleanupHostedService> logger) : IHostedService
{
/// <inheritdoc />
/// <summary>Terminates leftover orphan MXAccess worker processes once, best-effort, before the gateway starts accepting sessions.</summary>
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public Task StartAsync(CancellationToken cancellationToken)
{
try
@@ -25,6 +27,8 @@ public sealed class OrphanWorkerCleanupHostedService(
return Task.CompletedTask;
}
/// <inheritdoc />
/// <summary>No-op; this service has no ongoing work to stop.</summary>
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
@@ -28,7 +28,7 @@ internal sealed class SystemWorkerProcess(Process process) : IWorkerProcess
process.Kill(entireProcessTree);
}
/// <inheritdoc />
/// <summary>Disposes the wrapped <see cref="Process"/> instance.</summary>
public void Dispose()
{
process.Dispose();
@@ -78,10 +78,10 @@ public sealed class WorkerClient : IWorkerClient
_lastHeartbeatAt = _timeProvider.GetUtcNow();
}
/// <summary>Gets the worker's session ID.</summary>
/// <inheritdoc />
public string SessionId => _connection.SessionId;
/// <summary>Gets the worker process ID.</summary>
/// <inheritdoc />
public int? ProcessId
{
get
@@ -93,7 +93,7 @@ public sealed class WorkerClient : IWorkerClient
}
}
/// <summary>Gets the current client state.</summary>
/// <inheritdoc />
public WorkerClientState State
{
get
@@ -105,7 +105,7 @@ public sealed class WorkerClient : IWorkerClient
}
}
/// <summary>Gets the timestamp of the last received heartbeat.</summary>
/// <inheritdoc />
public DateTimeOffset LastHeartbeatAt
{
get
@@ -117,8 +117,7 @@ public sealed class WorkerClient : IWorkerClient
}
}
/// <summary>Starts the worker client and completes the handshake.</summary>
/// <param name="cancellationToken">Cancellation token.</param>
/// <inheritdoc />
public async Task StartAsync(CancellationToken cancellationToken)
{
ThrowIfDisposed();
@@ -141,11 +140,7 @@ public sealed class WorkerClient : IWorkerClient
_heartbeatLoopTask = Task.Run(HeartbeatLoopAsync);
}
/// <summary>Invokes a command on the worker and waits for reply.</summary>
/// <param name="command">The command to invoke.</param>
/// <param name="timeout">Command timeout.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The command reply.</returns>
/// <inheritdoc />
public async Task<WorkerCommandReply> InvokeAsync(
WorkerCommand command,
TimeSpan timeout,
@@ -228,9 +223,7 @@ public sealed class WorkerClient : IWorkerClient
}
}
/// <summary>Reads events from the worker as an async stream.</summary>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Async enumerable of worker events.</returns>
/// <inheritdoc />
public async IAsyncEnumerable<WorkerEvent> ReadEventsAsync(
[EnumeratorCancellation] CancellationToken cancellationToken)
{
@@ -242,9 +235,7 @@ public sealed class WorkerClient : IWorkerClient
}
}
/// <summary>Shuts down the worker gracefully.</summary>
/// <param name="timeout">Shutdown timeout.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <inheritdoc />
public async Task ShutdownAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
ThrowIfDisposed();
@@ -289,8 +280,7 @@ public sealed class WorkerClient : IWorkerClient
}
}
/// <summary>Terminates the worker process immediately.</summary>
/// <param name="reason">Reason for termination.</param>
/// <inheritdoc />
public void Kill(string reason)
{
ThrowIfDisposed();
@@ -302,6 +292,7 @@ public sealed class WorkerClient : IWorkerClient
}
/// <summary>Disposes the worker client and releases resources.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
public async ValueTask DisposeAsync()
{
if (_disposed)
@@ -390,13 +381,13 @@ public sealed class WorkerClient : IWorkerClient
}
/// <summary>
/// Monitors worker heartbeat and detects stale sessions. Mirrors
/// Worker-023 on the worker side: while a command is in flight on the
/// Monitors worker heartbeat and detects stale sessions. Mirrors the
/// worker-side watchdog: while a command is in flight on the
/// gateway↔worker pipe, the heartbeat watchdog is suppressed up to
/// <see cref="WorkerClientOptions.HeartbeatStuckCeiling"/> — the worker
/// may be busy executing a slow STA command and the heartbeat write may
/// be queued behind a long event-drain burst (Server-031), neither of
/// which indicates the worker is actually hung. Once the oldest pending
/// be queued behind a long event-drain burst, neither of which
/// indicates the worker is actually hung. Once the oldest pending
/// command exceeds the ceiling, the fault fires anyway so a truly stuck
/// COM call doesn't hide the worker forever.
/// </summary>
@@ -419,11 +410,6 @@ public sealed class WorkerClient : IWorkerClient
continue;
}
// Server-031: if a command is in flight and hasn't yet exceeded
// the stuck-command ceiling, the gap is more likely caused by
// pipe-write contention (event drain holding the writer lock)
// or a legitimately slow STA command than by a hung worker.
// Wait for the ceiling before faulting on heartbeat alone.
if (TryGetOldestPendingCommandAge(out TimeSpan oldestCommandAge)
&& oldestCommandAge <= _options.HeartbeatStuckCeiling)
{
@@ -446,7 +432,7 @@ public sealed class WorkerClient : IWorkerClient
/// Returns the age of the oldest pending command on the worker pipe,
/// measured via <see cref="TimeProvider.GetElapsedTime(long)"/> against
/// <see cref="PendingCommand.StartTimestamp"/>, or <c>false</c> when no
/// commands are pending. Used by the heartbeat watchdog (Server-031)
/// commands are pending. Used by the heartbeat watchdog
/// to decide whether a heartbeat gap is plausibly the result of
/// pipe-write contention rather than a hung worker.
/// </summary>
@@ -508,12 +494,12 @@ public sealed class WorkerClient : IWorkerClient
}
/// <summary>
/// Enqueues a worker event for client consumption. Server-032: the
/// channel is configured with <see cref="BoundedChannelFullMode.Wait"/>
/// and a brief consumer hiccup is now tolerated for up to
/// Enqueues a worker event for client consumption. The channel is
/// configured with <see cref="BoundedChannelFullMode.Wait"/>
/// and a brief consumer hiccup is tolerated for up to
/// <see cref="WorkerClientOptions.EventChannelFullModeTimeout"/>
/// (default 5s) before the worker is faulted. Pre-Server-032 the code
/// used <c>TryWrite</c> (non-blocking) which never honored the
/// (default 5s) before the worker is faulted. The channel previously
/// used <c>TryWrite</c> (non-blocking), which never honored the
/// configured <c>FullModeTimeout</c> — the worker faulted on the first
/// missed slot even though the wait-mode channel would have absorbed
/// the burst. The diagnostic now names the capacity, current depth, and
@@ -538,8 +524,6 @@ public sealed class WorkerClient : IWorkerClient
return;
}
// Channel is full; honor the configured wait timeout before declaring
// the consumer dead and faulting the worker (Server-032).
using CancellationTokenSource fullModeCts = CancellationTokenSource
.CreateLinkedTokenSource(cancellationToken);
fullModeCts.CancelAfter(_options.EventChannelFullModeTimeout);
@@ -15,7 +15,7 @@ public sealed class WorkerClientOptions
/// <summary>
/// Default ceiling on the in-flight-command heartbeat skip. Mirrors
/// <see cref="ZB.MOM.WW.MxGateway.Worker.Ipc.WorkerPipeSessionOptions.DefaultHeartbeatStuckCeiling"/>
/// on the worker side (Worker-023). When a command has been in flight
/// on the worker side. When a command has been in flight
/// longer than this, the gateway-side heartbeat watchdog fires
/// regardless of pending commands — a truly stuck COM call shouldn't
/// hide the worker forever.
@@ -47,8 +47,7 @@ public sealed class WorkerClientOptions
/// faulting the worker. Honored by <c>EnqueueWorkerEventAsync</c> via
/// <c>WriteAsync</c>; with the channel configured for
/// <c>BoundedChannelFullMode.Wait</c>, a transient backlog only faults
/// after the configured timeout has elapsed (Server-032). Pre-Server-032
/// the field was declared but unused — overflow faulted immediately.
/// after the configured timeout has elapsed.
/// </summary>
public TimeSpan EventChannelFullModeTimeout { get; init; }
@@ -56,12 +55,12 @@ public sealed class WorkerClientOptions
public int MaxPendingCommands { get; init; }
/// <summary>
/// Server-031: ceiling on the in-flight-command heartbeat-skip. When
/// Ceiling on the in-flight-command heartbeat-skip. When
/// a command has been pending on the gateway↔worker pipe for longer
/// than this, the gateway-side <c>HeartbeatLoopAsync</c> fires the
/// <c>HeartbeatExpired</c> fault even if commands are still pending;
/// a truly stuck COM call shouldn't keep the watchdog suppressed
/// indefinitely. Mirrors Worker-023's <c>HeartbeatStuckCeiling</c> on
/// indefinitely. Mirrors <c>HeartbeatStuckCeiling</c> on
/// the worker side.
/// </summary>
public TimeSpan HeartbeatStuckCeiling { get; init; }
@@ -30,6 +30,7 @@ public sealed class WorkerFrameWriter
/// </summary>
/// <param name="envelope">Worker envelope message to write.</param>
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public async ValueTask WriteAsync(
WorkerEnvelope envelope,
CancellationToken cancellationToken = default)
@@ -30,7 +30,7 @@ public sealed class WorkerProcessHandle : IDisposable
/// <summary>Gets the time when the process was launched.</summary>
public DateTimeOffset LaunchedAt { get; }
/// <inheritdoc />
/// <summary>Disposes the underlying worker process.</summary>
public void Dispose()
{
Process.Dispose();
@@ -58,12 +58,7 @@ public sealed class WorkerProcessLauncher : IWorkerProcessLauncher
_logger = logger ?? NullLogger<WorkerProcessLauncher>.Instance;
}
/// <summary>
/// Launches a worker process and waits for startup.
/// </summary>
/// <param name="request">Request payload.</param>
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
/// <returns>Handle to the launched worker process.</returns>
/// <inheritdoc />
public async Task<WorkerProcessHandle> LaunchAsync(
WorkerProcessLaunchRequest request,
CancellationToken cancellationToken = default)
@@ -2,11 +2,7 @@ namespace ZB.MOM.WW.MxGateway.Server.Workers;
public sealed class WorkerProcessStartedProbe : IWorkerStartupProbe
{
/// <summary>Verifies that the worker process has started and has not exited.</summary>
/// <param name="process">Worker process to verify.</param>
/// <param name="request">Process launch request.</param>
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
/// <returns>Completed task if process is running.</returns>
/// <inheritdoc />
public Task WaitUntilReadyAsync(
IWorkerProcess process,
WorkerProcessLaunchRequest request,
@@ -5,6 +5,7 @@ public static class WorkerServiceCollectionExtensions
{
/// <summary>Registers worker process launcher and factory services.</summary>
/// <param name="services">Service collection to register services.</param>
/// <returns>The same service collection, for chaining.</returns>
public static IServiceCollection AddWorkerProcessLauncher(this IServiceCollection services)
{
services.AddSingleton<IWorkerProcessFactory, SystemWorkerProcessFactory>();