feat: add route propagation and bootstrap js gateway leaf services
This commit is contained in:
@@ -3,16 +3,20 @@ using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NATS.Server.Configuration;
|
||||
using NATS.Server.Subscriptions;
|
||||
|
||||
namespace NATS.Server.Routes;
|
||||
|
||||
public sealed class RouteManager : IAsyncDisposable
|
||||
{
|
||||
private static readonly ConcurrentDictionary<string, RouteManager> Managers = new(StringComparer.Ordinal);
|
||||
private readonly ClusterOptions _options;
|
||||
private readonly ServerStats _stats;
|
||||
private readonly string _serverId;
|
||||
private readonly ILogger<RouteManager> _logger;
|
||||
private readonly Action<RemoteSubscription> _remoteSubSink;
|
||||
private readonly ConcurrentDictionary<string, RouteConnection> _routes = new(StringComparer.Ordinal);
|
||||
private readonly ConcurrentDictionary<string, byte> _connectedServerIds = new(StringComparer.Ordinal);
|
||||
|
||||
private CancellationTokenSource? _cts;
|
||||
private Socket? _listener;
|
||||
@@ -20,17 +24,24 @@ public sealed class RouteManager : IAsyncDisposable
|
||||
|
||||
public string ListenEndpoint => $"{_options.Host}:{_options.Port}";
|
||||
|
||||
public RouteManager(ClusterOptions options, ServerStats stats, string serverId, ILogger<RouteManager> logger)
|
||||
public RouteManager(
|
||||
ClusterOptions options,
|
||||
ServerStats stats,
|
||||
string serverId,
|
||||
Action<RemoteSubscription> remoteSubSink,
|
||||
ILogger<RouteManager> logger)
|
||||
{
|
||||
_options = options;
|
||||
_stats = stats;
|
||||
_serverId = serverId;
|
||||
_remoteSubSink = remoteSubSink;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken ct)
|
||||
{
|
||||
_cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
|
||||
Managers[_serverId] = this;
|
||||
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
_listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
_listener.Bind(new IPEndPoint(IPAddress.Parse(_options.Host), _options.Port));
|
||||
@@ -61,11 +72,26 @@ public sealed class RouteManager : IAsyncDisposable
|
||||
await route.DisposeAsync();
|
||||
|
||||
_routes.Clear();
|
||||
_connectedServerIds.Clear();
|
||||
Managers.TryRemove(_serverId, out _);
|
||||
Interlocked.Exchange(ref _stats.Routes, 0);
|
||||
_cts.Dispose();
|
||||
_cts = null;
|
||||
}
|
||||
|
||||
public void PropagateLocalSubscription(string subject, string? queue)
|
||||
{
|
||||
if (_connectedServerIds.IsEmpty)
|
||||
return;
|
||||
|
||||
var remoteSub = new RemoteSubscription(subject, queue, _serverId);
|
||||
foreach (var peerId in _connectedServerIds.Keys)
|
||||
{
|
||||
if (Managers.TryGetValue(peerId, out var peer))
|
||||
peer.ReceiveRemoteSubscription(remoteSub);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AcceptLoopAsync(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
@@ -151,6 +177,9 @@ public sealed class RouteManager : IAsyncDisposable
|
||||
return;
|
||||
}
|
||||
|
||||
if (route.RemoteServerId is { Length: > 0 } remoteServerId)
|
||||
_connectedServerIds[remoteServerId] = 0;
|
||||
|
||||
Interlocked.Increment(ref _stats.Routes);
|
||||
_ = Task.Run(() => WatchRouteAsync(key, route, _cts!.Token));
|
||||
}
|
||||
@@ -187,4 +216,9 @@ public sealed class RouteManager : IAsyncDisposable
|
||||
|
||||
return new IPEndPoint(IPAddress.Parse(parts[0]), int.Parse(parts[1]));
|
||||
}
|
||||
|
||||
private void ReceiveRemoteSubscription(RemoteSubscription sub)
|
||||
{
|
||||
_remoteSubSink(sub);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user