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.
This commit is contained in:
102
docs/plans/2026-03-01-server-boot-parity-design.md
Normal file
102
docs/plans/2026-03-01-server-boot-parity-design.md
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user