feat: execute full-repo remaining parity closure plan

This commit is contained in:
Joseph Doherty
2026-02-23 13:08:52 -05:00
parent cbe1fa6121
commit 2b64d762f6
75 changed files with 2325 additions and 121 deletions

View File

@@ -18,8 +18,10 @@ using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Publish;
using NATS.Server.LeafNodes;
using NATS.Server.Monitoring;
using NATS.Server.Mqtt;
using NATS.Server.Protocol;
using NATS.Server.Routes;
using NATS.Server.Server;
using NATS.Server.Subscriptions;
using NATS.Server.Tls;
using NATS.Server.WebSocket;
@@ -43,6 +45,8 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
private NatsOptions? _cliSnapshot;
private HashSet<string> _cliFlags = [];
private string? _configDigest;
private readonly SemaphoreSlim _reloadMu = new(1, 1);
private AcceptLoopErrorHandler? _acceptLoopErrorHandler;
private readonly Account _globalAccount;
private readonly Account _systemAccount;
private InternalEventSystem? _eventSystem;
@@ -58,6 +62,7 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
private readonly StreamManager? _jetStreamStreamManager;
private readonly ConsumerManager? _jetStreamConsumerManager;
private readonly JetStreamPublisher? _jetStreamPublisher;
private MqttListener? _mqttListener;
private Socket? _listener;
private Socket? _wsListener;
private readonly TaskCompletionSource _wsAcceptLoopExited = new(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -136,6 +141,15 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
public void WaitForShutdown() => _shutdownComplete.Task.GetAwaiter().GetResult();
internal Task AcquireReloadLockForTestAsync() => _reloadMu.WaitAsync();
internal void ReleaseReloadLockForTest() => _reloadMu.Release();
internal void SetAcceptLoopErrorHandlerForTest(AcceptLoopErrorHandler handler) => _acceptLoopErrorHandler = handler;
internal void NotifyAcceptErrorForTest(Exception ex, EndPoint? endpoint, TimeSpan delay) =>
_acceptLoopErrorHandler?.OnAcceptError(ex, endpoint, delay);
public async Task ShutdownAsync()
{
if (Interlocked.CompareExchange(ref _shutdown, 1, 0) != 0)
@@ -202,6 +216,8 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
// Stop monitor server
if (_monitorServer != null)
await _monitorServer.DisposeAsync();
if (_mqttListener != null)
await _mqttListener.DisposeAsync();
DeletePidFile();
DeletePortsFile();
@@ -534,6 +550,12 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
await _gatewayManager.StartAsync(linked.Token);
if (_leafNodeManager != null)
await _leafNodeManager.StartAsync(linked.Token);
if (_options.Mqtt is { Port: > 0 } mqttOptions)
{
var mqttHost = string.IsNullOrWhiteSpace(mqttOptions.Host) ? _options.Host : mqttOptions.Host;
_mqttListener = new MqttListener(mqttHost, mqttOptions.Port);
await _mqttListener.StartAsync(linked.Token);
}
if (_jetStreamService != null)
{
await _jetStreamService.StartAsync(linked.Token);
@@ -554,7 +576,7 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
Socket socket;
try
{
socket = await _listener.AcceptAsync(linked.Token);
socket = await _listener!.AcceptAsync(linked.Token);
tmpDelay = AcceptMinSleep; // Reset on success
}
catch (OperationCanceledException)
@@ -570,6 +592,7 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
if (IsShuttingDown || IsLameDuckMode)
break;
_acceptLoopErrorHandler?.OnAcceptError(ex, _listener?.LocalEndPoint, tmpDelay);
_logger.LogError(ex, "Temporary accept error, sleeping {Delay}ms", tmpDelay.TotalMilliseconds);
try { await Task.Delay(tmpDelay, linked.Token); }
catch (OperationCanceledException) { break; }
@@ -624,8 +647,13 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
private async Task AcceptClientAsync(Socket socket, ulong clientId, CancellationToken ct)
{
var reloadLockHeld = false;
NatsClient? client = null;
try
{
await _reloadMu.WaitAsync(ct);
reloadLockHeld = true;
// Rate limit TLS handshakes
if (_tlsRateLimiter != null)
await _tlsRateLimiter.WaitAsync(ct);
@@ -673,14 +701,30 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
}
var clientLogger = _loggerFactory.CreateLogger($"NATS.Server.NatsClient[{clientId}]");
var client = new NatsClient(clientId, stream, socket, _options, clientInfo,
client = new NatsClient(clientId, stream, socket, _options, clientInfo,
_authService, nonce, clientLogger, _stats);
client.Router = this;
client.TlsState = tlsState;
client.InfoAlreadySent = infoAlreadySent;
_clients[clientId] = client;
}
catch (Exception ex)
{
_logger.LogDebug(ex, "Failed to accept client {ClientId}", clientId);
try { socket.Shutdown(SocketShutdown.Both); } catch { }
socket.Dispose();
return;
}
finally
{
if (reloadLockHeld)
_reloadMu.Release();
}
await RunClientAsync(client, ct);
try
{
if (client != null)
await RunClientAsync(client, ct);
}
catch (Exception ex)
{
@@ -708,6 +752,7 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
catch (SocketException ex)
{
if (IsShuttingDown || IsLameDuckMode) break;
_acceptLoopErrorHandler?.OnAcceptError(ex, _wsListener?.LocalEndPoint, tmpDelay);
_logger.LogError(ex, "Temporary WebSocket accept error, sleeping {Delay}ms", tmpDelay.TotalMilliseconds);
try { await Task.Delay(tmpDelay, ct); } catch (OperationCanceledException) { break; }
tmpDelay = TimeSpan.FromTicks(Math.Min(tmpDelay.Ticks * 2, AcceptMaxSleep.Ticks));
@@ -1407,6 +1452,8 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
Name = client.ClientOpts?.Name ?? "",
Lang = client.ClientOpts?.Lang ?? "",
Version = client.ClientOpts?.Version ?? "",
AuthorizedUser = client.ClientOpts?.Username ?? "",
Account = client.Account?.Name ?? "",
InMsgs = Interlocked.Read(ref client.InMsgs),
OutMsgs = Interlocked.Read(ref client.OutMsgs),
InBytes = Interlocked.Read(ref client.InBytes),
@@ -1415,7 +1462,11 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
Rtt = client.Rtt,
TlsVersion = client.TlsState?.TlsVersion ?? "",
TlsCipherSuite = client.TlsState?.CipherSuite ?? "",
TlsPeerCertSubject = client.TlsState?.PeerCert?.Subject ?? "",
MqttClient = "", // populated when MQTT transport is implemented
JwtIssuerKey = string.IsNullOrEmpty(client.ClientOpts?.JWT) ? "" : "present",
JwtTags = "",
Proxy = client.ClientOpts?.Username?.StartsWith("proxy:", StringComparison.Ordinal) == true ? "true" : "",
});
// Cap closed clients list
@@ -1667,6 +1718,7 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
_routeManager?.DisposeAsync().AsTask().GetAwaiter().GetResult();
_gatewayManager?.DisposeAsync().AsTask().GetAwaiter().GetResult();
_leafNodeManager?.DisposeAsync().AsTask().GetAwaiter().GetResult();
_mqttListener?.DisposeAsync().AsTask().GetAwaiter().GetResult();
_jetStreamService?.DisposeAsync().AsTask().GetAwaiter().GetResult();
_stats.JetStreamEnabled = false;
foreach (var client in _clients.Values)