Skip to content

fix(web): register CLI stop signals before printing readiness - #401

Open
tt-a1i wants to merge 3 commits into
mainfrom
hive/delivery-cli-ready-signals
Open

fix(web): register CLI stop signals before printing readiness#401
tt-a1i wants to merge 3 commits into
mainfrom
hive/delivery-cli-ready-signals

Conversation

@tt-a1i

@tt-a1i tt-a1i commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Register SIGINT/SIGTERM with process.once immediately after host.start(), before readiness output. Tests that send SIGTERM on the ready line can otherwise observe exitCode === null / signal === "SIGTERM" instead of the CLI stop path.

Keep once (not on). A second same signal while stop() is in flight falls through to Node default termination.

Tests:

  • Source-order lock that process.once(signal, onStopSignal) is registered before readiness output.
  • Single-fire SIGTERM on stop-failure: exitCode === 1, signal === null, stderr includes stop failed. Unchanged.
  • Hang-stop publishes entered via same-dir write-then-rename, then writes stop-entered on stderr. Parent waits for file contents, woken by directory watch or that stderr, records first kill() delivery, and on timeout inspects final + staging paths. waitForPath existence-only is gone.

Does not include the #355 peer-entry resolver. Does not land inside #373. Production bin/openpi.js is unchanged by the hang-stop follow-ups.

Test plan

  • Isolated head: bun run check; tests/web/cli.test.ts 4/4 on Node 26.3.0 and portable Node 22.19.0 Darwin
  • Frozen 11765a3 probe (external, not in tree): Node 26 12/12 and Node 22 12/12 first-kill true; Node 22 watch order is stop-entered.tmp then stop-entered
  • Frozen 11765a3 file hang-stop ×10 Node 22 Darwin: 10/10. Did not reproduce Pascal's 1/10 timeout
  • Isolated bun run test: 1340 / pass 1337 / fail 2 / skip 1. Hang-stop passed. Failures are plan-mode result-rendering only. Vitest skipped by runner; separate official Vitest 30/30 EXIT=0
  • CI 6e7ca46 https://github.com/openpi-dev/openpi/actions/runs/33943551441 : Node 22.19.0 / Node 24 / Windows all pass. Node 22 hang-stop ok 1222; Node 22 packed standalone Web CLI smoke ran and the job completed (no kill: No such process). Windows hang-stop is a no-op return (ok 1129)
  • Windows CI job passed; POSIX signal tests are a no-op on Windows, not a Windows signal proof

Pascal's 1/10 stopMarker 5s timeout with a live child is retained as fact. It is not attributed to signal-before-handler: production registers process.once before readiness. Whether that timeout was a missed rename watch or first SIGTERM never entering stop() is unknown.

Register SIGINT/SIGTERM with process.once after host.start and before
readiness so a SIGTERM at ready cannot miss the handler. Keep once so a
second same signal can still default-terminate while stop is in flight.
waitForPath only stats existence, so a direct writeFile can let the
parent observe an empty stop-entered file before contents land.
Directory watch can fire first for the staging rename and miss the
final name. Record first SIGTERM delivery and inspect both paths on
timeout.
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