Skip to content

fix: graceful shutdown and dynamic port resolution#20

Merged
cursor[bot] merged 4 commits intomainfrom
fix/server-shutdown-and-port-resolution
Feb 21, 2026
Merged

fix: graceful shutdown and dynamic port resolution#20
cursor[bot] merged 4 commits intomainfrom
fix/server-shutdown-and-port-resolution

Conversation

@holiber
Copy link
Copy Markdown
Owner

@holiber holiber commented Feb 21, 2026

Three bug fixes for createTerminalServer():

  1. Port 0 resolution: When called with port=0 (random OS port), the returned port was always 0 instead of the actual assigned port. Now reads the real port from wss.address() after listening.

  2. Async listening: Wait for the WebSocketServer 'listening' event before reading wss.address(), ensuring the port is available.

  3. Graceful shutdown: Close all WebSocket clients before killing PTY processes. Previously, killing PTYs while clients were connected caused node-pty to throw an uncatchable native C++ exception (libc++abi: terminating due to uncaught Napi::Error), which crashed the host process with SIGABRT.

Three bug fixes for createTerminalServer():

1. Port 0 resolution: When called with port=0 (random OS port),
   the returned port was always 0 instead of the actual assigned port.
   Now reads the real port from wss.address() after listening.

2. Async listening: Wait for the WebSocketServer 'listening' event
   before reading wss.address(), ensuring the port is available.

3. Graceful shutdown: Close all WebSocket clients before killing PTY
   processes. Previously, killing PTYs while clients were connected
   caused node-pty to throw an uncatchable native C++ exception
   (libc++abi: terminating due to uncaught Napi::Error), which
   crashed the host process with SIGABRT.
@holiber holiber force-pushed the fix/server-shutdown-and-port-resolution branch from a3ddcd1 to 04cfc66 Compare February 21, 2026 22:52
@holiber
Copy link
Copy Markdown
Owner Author

holiber commented Feb 21, 2026

@cursoragent please review this upcoming PR

@cursor
Copy link
Copy Markdown
Contributor

cursor Bot commented Feb 21, 2026

Thanks — I reviewed PR #20.

  • Main fix looks good: the new two-phase shutdown in src/server/jabtermServer.ts (close/terminate WS clients, brief wait, then kill PTYs) is a sensible mitigation for the node-pty SIGABRT crash during teardown.
  • PR description/commit message mismatch: the “port=0 resolution” + “wait for listening before reading address” parts appear to already be in main; this PR’s diff is effectively the shutdown sequencing + some formatting. I’d update the PR description to reflect what’s actually changed.
  • A couple of nits/edge cases:
    • close() isn’t fully idempotent under concurrent calls: a second call during the first call’s pre-closePromise window returns Promise.resolve() early. Consider setting closePromise immediately at the top of close() and returning it for all callers.
    • Unrelated to this diff but relevant to the PR text: the CLI currently can’t do --port 0 because it uses args.port || ... (0 gets treated as “unset”). Using args.port ?? ... would fix it.

Overall: LGTM for the shutdown fix; I’d just tweak the PR text and consider the close() concurrency/idempotency improvement (either here or as a follow-up).

Open in Web Open in Cursor 

@holiber
Copy link
Copy Markdown
Owner Author

holiber commented Feb 21, 2026

@cursoragent
Let add your changes that you think are good to add, and make sure ci is green for this PR after your changes

@cursor
Copy link
Copy Markdown
Contributor

cursor Bot commented Feb 21, 2026

What I changed (pushed to fix/server-shutdown-and-port-resolution)

  • Fixed true idempotency for shutdown: createJabtermServer().close() now returns the same closePromise for concurrent callers, avoiding the race where a second caller could get an immediate resolved no-op. (src/server/jabtermServer.ts)
  • Fixed CLI --port 0: bin/jabterm-server.mjs now uses args.port ?? envPort, so passing --port 0 correctly results in an ephemeral port instead of being treated as “unset”.

Commit: 4869563 (“fix: idempotent close() and allow --port 0”)

CI / tests

  • Ran pnpm run test:smoke successfully: SMOKE: 2/2 passed in 3.8s.
    (Initial failure was just missing Playwright browsers in this fresh environment; after installing browsers + OS deps locally, smoke is green.)

If you want, I can also update the PR description to match the actual diff (since port=0/listening fixes appear to already be in main).

Open in Web Open in Cursor 

Co-authored-by: Alexander Nazarov <holiber@users.noreply.github.com>
@holiber
Copy link
Copy Markdown
Owner Author

holiber commented Feb 21, 2026

@cursoragent
Add tests for the changes

@cursor
Copy link
Copy Markdown
Contributor

cursor Bot commented Feb 21, 2026

Added tests + small refactors to make them reliable (pushed)

I implemented unit tests for the changes and pushed them to fix/server-shutdown-and-port-resolution:

  • New CLI unit tests: added src/server/cli.ts with pure helpers parseCliArgs() + resolveCliPort(), and tests that assert --port 0 is preserved (doesn’t fall back to env/default). (tests/unit/server/cli.test.ts)
  • New shutdown unit test: added a test that starts createJabtermServer(), opens a WS connection (with node-pty mocked), calls close() twice concurrently, and verifies it’s idempotent and closes the connection cleanly. (tests/unit/server/close-idempotent.test.ts)
  • Small implementation tweak: changed close() to be a non-async function so concurrent callers truly get the same promise instance (no async wrapper promise), strengthening the idempotency guarantee.

Verification

  • Ran pnpm run test:unit: all unit tests passed.
  • Ran pnpm run test:smoke: green.

Commit pushed: 1e6ac8b (“test: cover shutdown idempotency and --port 0”).

Open in Web Open in Cursor 

Co-authored-by: Alexander Nazarov <holiber@users.noreply.github.com>
@holiber
Copy link
Copy Markdown
Owner Author

holiber commented Feb 21, 2026

@cursoragent nice, merge it and make a new release! Add notes to the PRs in changelog

@cursor
Copy link
Copy Markdown
Contributor

cursor Bot commented Feb 21, 2026

Done — merged + released with changelog notes

Open in Web Open in Cursor 

Co-authored-by: Alexander Nazarov <holiber@users.noreply.github.com>
@cursor cursor Bot merged commit e4ed68e into main Feb 21, 2026
1 check passed
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.

2 participants