From ca8297d0ad0d0cac3e8845195ac1855e2948bbc5 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sun, 1 Mar 2026 14:47:50 -0500 Subject: [PATCH] docs: add server boot parity design Design for wiring NatsServer.Start() to call all subsystem startup methods matching Go's Server.Start() sequence, enabling a fully booting server that accepts client connections. --- .../2026-03-01-server-boot-parity-design.md | 102 ++++++++++++++++++ reports/current.md | 2 +- 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 docs/plans/2026-03-01-server-boot-parity-design.md diff --git a/docs/plans/2026-03-01-server-boot-parity-design.md b/docs/plans/2026-03-01-server-boot-parity-design.md new file mode 100644 index 0000000..c8777dc --- /dev/null +++ b/docs/plans/2026-03-01-server-boot-parity-design.md @@ -0,0 +1,102 @@ +# Server Boot Parity Design + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers-extended-cc:executing-plans to implement this plan task-by-task. + +**Goal:** Wire up `NatsServer.Start()` to call all subsystem startup methods in the same order as Go's `Server.Start()`, enabling a fully booting server that accepts client connections. + +**Architecture:** The .NET port already has every subsystem startup method implemented (`AcceptLoop`, `StartMonitoring`, `EnableJetStream`, `StartRouting`, `StartGateways`, `StartLeafNodeAcceptLoop`, `StartWebsocketServer`, etc.). The only gap is that `Start()` (in `NatsServer.Init.cs:976–1037`) stops after system account setup instead of continuing through the full startup sequence. The fix is wiring — calling existing methods in the correct order — plus 3 trivial no-op stubs for missing minor methods and guarding the MQTT `NotImplementedException`. + +**Tech Stack:** .NET 10, C# latest, xUnit, NATS.Client.Core (for validation test) + +--- + +## Problem Statement + +The .NET `Start()` method currently: +1. Logs version/name info +2. Sets `_running = 1` +3. Enables leafnode flag +4. Writes PID file +5. Sets up system account +6. Starts OCSP response cache +7. Signals `_startupComplete` and logs "Server is ready" + +It is missing ~15 subsystem calls that Go's `Start()` makes between steps 5 and 7. + +## Design + +### 1. Complete `Start()` Body + +Insert the following calls in `NatsServer.Init.cs` between the system account setup and the "Server is ready" log, matching Go `server.go:2263–2575`: + +``` +CheckAuthForWarnings() -- new no-op stub +StartRateLimitLogExpiration() -- exists in Lifecycle.cs +StartProfiler() if ProfPort != 0 -- exists (stub) in Listeners.cs +Log config file info -- opts.ConfigFile notice +Log trusted operators -- opts.TrustedOperators loop +StartMonitoring() -- exists in Listeners.cs +AccountResolver.Start() if resolver != null -- exists +StartGWReplyMapExpiration() -- exists in Gateways.ReplyMap.cs +EnableJetStream(cfg) if opts.JetStream -- exists in JetStreamCore.cs + else: check accounts for JS limits -- exists (EnableJetStreamAccounts pattern) +StartDelayedApiResponder() -- new no-op stub +StartOCSPMonitoring() -- exists in Ocsp.cs +InitOCSPResponseCache() -- exists (StartOCSPResponseCache) +StartGateways() if Gateway.Port != 0 -- exists in Gateways.ConfigAndStartup.cs +StartWebsocketServer() if Websocket.Port != 0 -- exists in WebSocket.cs +StartLeafNodeAcceptLoop() if LeafNode.Port != 0 -- exists in LeafNodes.ConfigAndConnect.cs +SolicitLeafNodeRemotes() if remotes.Count > 0 -- exists in LeafNodes.ConfigAndConnect.cs +StartMqtt() if MQTT.Port != 0 -- guard NotImplementedException +StartRouting() if Cluster.Port != 0 -- exists in Routes.Connections.cs +LogPorts() if PortsFileDir != empty -- new no-op stub +Signal _startupComplete -- move to here (from current position) +AcceptLoop() if !DontListen -- exists in Listeners.cs +StartOCSPResponseCache() -- exists (move to after AcceptLoop) +Noticef("Server is ready") -- move to end +``` + +### 2. New Method Stubs + +**`CheckAuthForWarnings()`** — `NatsServer.Auth.cs` +- No-op. In Go this logs warnings about insecure auth configs. Can be implemented later. + +**`StartDelayedApiResponder()`** — `NatsServer.JetStreamCore.cs` +- Starts a background task that will process delayed JetStream API responses. +- Initial implementation: no-op goroutine that exits when `_quitCts` cancels. + +**`LogPorts()`** — `NatsServer.Init.cs` +- No-op. Writes ports info to file when `PortsFileDir` configured. Minor utility. + +### 3. MQTT Guard + +Change `MqttServerExtensions.StartMqtt()` from throwing `NotImplementedException` to logging a warning and returning. This prevents `Start()` from crashing when MQTT port is configured. + +### 4. Validation Test + +New test file: `dotnet/tests/ZB.MOM.NatsNet.Server.IntegrationTests/ServerBootTests.cs` + +Test: `ServerBoot_AcceptsClientConnection_ShouldSucceed` +- Creates server with ephemeral port, JetStream enabled, temp store dir +- Calls `Start()` +- Connects with `NATS.Client.Core.NatsConnection` +- Publishes to `test.subject` and verifies subscribe receives message +- Calls `Shutdown()` + +### 5. Files Changed + +| File | Change | +|------|--------| +| `NatsServer.Init.cs` | Complete `Start()` body, add `LogPorts()` stub | +| `NatsServer.Auth.cs` | Add `CheckAuthForWarnings()` stub | +| `NatsServer.JetStreamCore.cs` | Add `StartDelayedApiResponder()` stub | +| `Mqtt/MqttHandler.cs` | Guard `StartMqtt()` to not throw | +| `ServerBootTests.cs` | New integration test | + +### 6. Success Criteria + +- `dotnet build` passes with 0 errors +- Existing unit tests still pass (2659 pass, 53 skip) +- Existing integration tests still pass (113 pass, 854 skip, 0 fail) +- New `ServerBoot_AcceptsClientConnection_ShouldSucceed` test passes +- Server logs show full startup sequence matching Go's output pattern diff --git a/reports/current.md b/reports/current.md index 41779f4..d2ebd51 100644 --- a/reports/current.md +++ b/reports/current.md @@ -1,6 +1,6 @@ # NATS .NET Porting Status Report -Generated: 2026-03-01 18:41:43 UTC +Generated: 2026-03-01 19:47:52 UTC ## Modules (12 total)