Repository navigation
test: keep the lifecycle tests stable on a slow runner and cut fixed waits - #311
Conversation
…waits - destroy --force before the host names the program: a held host never answers create, which gave up after about 5 s and sent the host SIGTERM. On a slow macOS runner that came before the program's destroy, which then read SESSION_ALREADY_DESTROYED or died with the program. The test now kills create once the program runs and holds the host's write until the destroy kills the host. - replay-hold.mjs: REPLAY_RELEASE=<file> ends a hold early. The create give-up tests release the host's write once create has exited instead of after a fixed 10 s. - Tests wait for the crashed host to end instead of a fixed sleep, and the offline snapshot test waits for the program's output in the log. - The file's per-test time-out is 60 s: a runner three times slower than usual took 33 s for the stale host recovery test.
|
@codex review |
|
@codex security review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
🛡️ Codex Security ReviewSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
|
Codex Review: Didn't find any major issues. Delightful! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Why
On a slow macOS runner, merge-group run 41718251342 failed
test/integration/lifecycle.test.ts"destroy --force before the host names the program prints its result" after 2 retries. "stale host recovery" needed 2 retries (99 s), and the file took 527 s instead of the usual 230 s. That runner ran every test 2 to 4 times slower than usual: "full lifecycle" took 19 s instead of 5 s. In 50 macOS jobs from 2026-11-03, this was the only failure of that test.Cause
create.creategives up after about 5 s and sends the host SIGTERM. The test passed only while the program's innerdestroy --forcekilled the host before that SIGTERM. Thatdestroy --forceneeds two Node starts, because it runs itself again in a new session. On a slow runner the SIGTERM came first, and the host shut the session down itself. Then the inner destroy readSESSION_ALREADY_DESTROYED(ok: false), or the host's hang-up killed it before it printed anything. This is not a product bug: a destroy whose session another actor ended reports that.I reproduced cause 1 on Linux with a preload that delays the start of the host and of each
destroyCLI (Atomics.wait). Main fails 3 of 3 with a delay of 1.5 s (ok: false,SESSION_ALREADY_DESTROYED) and 3 of 3 with 2.5 s (no envelope). This branch passes with both delays.Repro preload (not committed)
What changes
Only tests and the
replay-hold.mjstest helper change. The product code does not change.createin the background and kills it once the program runs, so no give-up SIGTERM reaches the host. It holds the host's start-up write until the innerdestroy --forcekills the host. It also checks thatchildPidstaysnull, so the destroy really ran before the host named the program. Before, a destroy that ran after the 4 s hold also passed.replay-hold.mjs.REPLAY_RELEASE=<file>ends a hold as soon as the file exists, so the hold time is only a cap. The two "a create that gives up" tests release the host's write oncecreatehas exited, instead of after a fixed 10 s. That is about 3 s faster per test, and the test no longer depends oncreategiving up within 10 s.processEnds, andcrashSessionreturns the host's pid). The offline snapshot test waited 1 s for the program's output. It now waits untilevents.jsonlcontains that output.What I did not cut
Most of the file's real time is product timing: the 5 s destroy wait before
HOST_TIMEOUT, the 2 s shutdown grace, and about 0.7 s per CLI start throughtsx. The tests that checkHOST_TIMEOUTmust wait out the destroy wait. Cutting it needs a test-only timing setting in the product code. I did not add one.Validation
tsc --noEmit,oxlintandoxfmt --checkpass.8064471d, fix: create stops its host and names the session on every error of its readiness wait #294), with no retries, 7 of 7 tests pass. The early-destroy test took 4.2 to 4.7 s on this branch and 6.7 to 7.1 s on main, run back to back on the same host.--maxWorkers=1 --retry=2on this shared host at load averages of 30 to 80. This branch passed 63 of 63 in 491 s. Main failed 1 test in 730 s: "destroy of an exited session from a CLI that sees no /proc, in the pid namespace of the host" hit the 30 s time-out 3 times. On main, the early-destroy test also needed 2 retries.Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:xhigh