feat: execute full-repo remaining parity closure plan
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user