Skip to content

test: scale broker/app-server spawn timeouts under CPU contention (#53) - #54

Merged
axisrow merged 1 commit into
mainfrom
ao/codex-plugin-cc-10/fix-flaky-5s-timeouts
Aug 3, 2026
Merged

test: scale broker/app-server spawn timeouts under CPU contention (#53)#54
axisrow merged 1 commit into
mainfrom
ao/codex-plugin-cc-10/fix-flaky-5s-timeouts

Conversation

@axisrow

@axisrow axisrow commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Fixes #53.

What was wrong

Concurrent npm test runs made unrelated tests fail at almost exactly 5000 ms. Both offenders budget real process spawns, not logic:

  • broker-smoke.test.mjsonceMessage(child, "ready") waits for a real broker fork plus a real fake-codex app-server.
  • broker-client-initialize-timeout.test.mjs — the HANG watchdogs race a withAppServer fallback that spawns a direct app-server.

Under contention these lose the race against the machine instead of catching a defect.

The fix

scaleTimeout() in tests/helpers.mjs, applied to those budgets.

The multiplier is a flat base, not an os.loadavg() derivation. I tried loadavg first and it did not work: it is a 1-minute average, so it still reads near-idle during the first seconds of a burst — exactly when these deadlines are computed. Measured on a 10-core box, ten concurrent test processes produced a load-derived multiplier of 1 while the work needed ~4x, and the suite still failed at a flat 5000 ms. loadavg is kept only as a floor, for the case where it has genuinely caught up (a CI box already busy at start).

Handshake deadlines that are themselves under test (300/500 ms) stay unscaled — scaling them would make the assertion meaningless.

Side fix: leaked watchdog timers

Scaling the budgets surfaced a pre-existing bug. A bare setTimeout inside a Promise.race keeps the event loop alive for the full budget even when the real promise wins. At 5 s it was invisible; at 30 s it inflated the file from 6.7 s to 31.5 s wall-clock despite every test passing. A raceHang() helper now clears the losing timer — the two files run in 2.98 s, faster than before this change.

Verification

On a 10-core box, 10 concurrent runs of the two files:

before after
10-way contention 10/10 red 10/10 green
  • Isolated: 5/5 green, per-test durations unchanged (scaling costs nothing on a green run — the wait resolves the moment the event arrives).
  • Full suite: 194/194 green.
  • tsc -p tsconfig.app-server.json: clean.

Known boundary

Beyond ~10 concurrent runs (1x cores) failures still occur, but they change character: they hit the production SPAWNED_INITIALIZE_TIMEOUT_MS (10 s) in app-server.mjs, reported as codex app-server initialize timed out. That is a genuine signal about the system exceeding its own production budget at 1.6x oversubscription, not a test flake, so I deliberately left it alone — changing it would alter product behavior, which is out of scope for this issue. The scenario reported in #53 (three simultaneous npm test runs) is covered with a wide margin.

Test-only change; no version bump.

🤖 Generated with Claude Code

https://claude.ai/code/session_0185ypzB1bqu9CLxTVyWdrzx

Concurrent `npm test` runs made unrelated tests fail at almost exactly
5000ms: the broker-smoke IPC-ready wait and the withAppServer fallback
watchdogs budget real process spawns, so under contention they lost the
race against the machine rather than catching a logic defect.

Add scaleTimeout() in tests/helpers.mjs and apply it to those budgets.
The multiplier is a flat base rather than an os.loadavg() derivation:
loadavg is a 1-minute average that still reads near-idle during the
first seconds of a burst, which is exactly when these deadlines are
computed — a load-derived multiplier measured 1x while the work needed
4x, and the suite still failed at a flat 5000ms. loadavg is kept only
as a floor for the case where it has caught up. Handshake deadlines
that are themselves under test (300/500ms) stay unscaled.

Also clear the losing watchdog timer via a raceHang() helper. A bare
setTimeout in a Promise.race keeps the event loop alive for the full
budget even when the real promise wins; scaling the budget exposed this,
inflating the file from 6.7s to 31.5s wall-clock. Clearing it brings the
two files to 2.98s, faster than before this change.

Verified on a 10-core box: 10 concurrent runs of the two files went
10/10 red before, 10/10 green after. Beyond ~10 (1x cores) the failures
change character — they hit the production SPAWNED_INITIALIZE_TIMEOUT_MS
(10s) in app-server.mjs, which is a genuine signal and deliberately left
alone. Full suite 194/194 green; tsc build clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0185ypzB1bqu9CLxTVyWdrzx
@axisrow

axisrow commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

Filed the production-side boundary noted above as #55 — the spawned app-server initialize has a hard 10s deadline (SPAWNED_INITIALIZE_TIMEOUT_MS) with no user-facing override. This PR still deliberately leaves that constant alone; #55 tracks it separately.

@axisrow

axisrow commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@claude @codex review PR #54 at exact head 5211a84 (round 5038f345-2cfb-4ed0-bfdd-a262aabc6fe8). Focus on critical issues: bugs, security vulnerabilities, logical errors, data loss risks, performance problems. Do NOT nitpick style, naming conventions, minor formatting, or subjective preferences — only flag issues that could break functionality or cause real harm in production.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 5211a84822

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

@axisrow

axisrow commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@claude review PR #54 at exact head 5211a84 (round 4fd3773e-1c4a-4c11-bbcd-fa195fb33ea4). Focus on critical issues: bugs, security vulnerabilities, logical errors, data loss risks, performance problems. Do NOT nitpick style, naming conventions, minor formatting, or subjective preferences — only flag issues that could break functionality or cause real harm in production.

@axisrow

axisrow commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@claude review PR #54 at exact head 5211a84 (round 4ef08a3b-4f6e-47f3-9204-a8c4fec6a04c). Focus on critical issues: bugs, security vulnerabilities, logical errors, data loss risks, performance problems. Do NOT nitpick style, naming conventions, minor formatting, or subjective preferences — only flag issues that could break functionality or cause real harm in production.

@axisrow
axisrow merged commit 9d0bac5 into main Aug 3, 2026
@axisrow
axisrow deleted the ao/codex-plugin-cc-10/fix-flaky-5s-timeouts branch August 3, 2026 05:51
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.

Tests flake under parallel load: hard 5s timeouts lose races against CPU contention

1 participant