Skip to content

feat(sdk): add Surfnet.stop() for graceful shutdown#642

Open
amilz wants to merge 3 commits intosolana-foundation:mainfrom
amilz:feat/dev-467-add-surfnet-stop
Open

feat(sdk): add Surfnet.stop() for graceful shutdown#642
amilz wants to merge 3 commits intosolana-foundation:mainfrom
amilz:feat/dev-467-add-surfnet-stop

Conversation

@amilz
Copy link
Copy Markdown

@amilz amilz commented Apr 30, 2026

Summary

  • Add Surfnet::stop(&mut self) to the Rust SDK that sends SimnetCommand::Terminate and blocks until both RPC servers (HTTP + WS) acknowledge shutdown via SimnetEvent::Shutdown, with a 5s timeout.
  • Returns an error when shutdown is not confirmed so callers can treat unfreed ports as fatal instead of silently leaking sockets.
  • Surface stop() through the napi binding and TypeScript wrapper so consumers can call surfnet.stop() from afterAll test teardown.
  • Drop keeps its best-effort Terminate send when stop() was not called or failed.
  • Install a no-op log::Log on first surfnet boot in sdk-node to silence parity-ws's hardcoded println! fallback that fires on every client-side WS reset on macOS (parity-ws only ignores ECONNRESET when errno == 104 (Linux); macOS ECONNRESET is 54). Only registers when no logger is already installed, leaving host-configured loggers untouched.

Test Plan

  • cargo test -p surfpool-sdk -p surfpool-sdk-node — passes (22 + 0 tests).
  • npm test in crates/sdk-node/ — passes (6/6) including a new smoke test that calls stop() twice (idempotency on success), confirms the RPC fails after, and verifies the port is rebindable.
  • Full workspace cargo test --workspace — pre-existing flake in surfpool-core unrelated to this change (verified by stashing the diff).
  • Verified sdk-node consumers no longer see Encountered an error: ... Enable a logger to see more information. on stderr during normal client disconnects on macOS.

Closes DEV-467

(Replaces #641)

amilz added 3 commits April 30, 2026 13:58
Expose a JS-callable shutdown that closes the HTTP + WebSocket RPC
servers and frees the bound port. Blocks until both servers
acknowledge shutdown (via SimnetEvent::Shutdown) or the 5s timeout
elapses; returns an error if shutdown is not confirmed so callers
can treat it as fatal rather than silently leaking sockets.

Use this from test teardown (e.g. afterAll) to avoid 'connection
reset' / 'broken pipe' warnings caused by the OS yanking sockets at
process exit.

Drop still sends Terminate as a best-effort fallback when stop()
was not called or failed.

Closes DEV-467
Install a no-op log::Log on first surfnet boot so parity-ws skips its
hardcoded println! fallback when a WS client closes uncleanly. parity-ws
only ignores ECONNRESET when errno == 104 (Linux); on macOS ECONNRESET
is 54, so the fallback fires on every client-side reset and pollutes
stderr in test runners. Installing any logger makes log_enabled!(Error)
return true, suppressing the println.

Only mutates global log state when no logger is already registered, so
host-installed loggers keep their configured max level.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant