Files
natsnet/docs/plans/2026-03-01-server-boot-parity-design.md
Joseph Doherty ca8297d0ad 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 14:47:50 -05:00

5.1 KiB
Raw Permalink Blame History

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:9761037) 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:22632575:

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