test: replace jest workers past 200 MB so they exit in time (closes #766) #774

Merged
clawbot merged 1 commits from issue-766-run-tests-in-band into next 2026-11-11 09:37:13 +01:00
Collaborator

Implements the decision in
#774 (comment). No test
leaks a handle
(#766 (comment)). On a
starved CPU, workers holding 380 to 970 MB could not exit within the 500 ms
jest allows, and script/lib/jest.js failed the run.

  • package.json: workerIdleMemoryLimit of 200MB in the jest section.
    After each test file, a worker whose heap is over 200 MB is replaced by a
    fresh one.
  • tests/jestRunner.test.js runs script/lib/jest.js on
    tests/fixtures/leavesIntervalRunning.js, which leaves an interval running,
    and expects the force-stop to fail the run. The memory limit makes jest use a
    worker process even for this one file. eslint.config.js gives
    tests/fixtures/ the jest globals.
  • script/lib/jest.js, the Dockerfile and README.md are as on next.

Measured on 08adee9: three workers pinned to one core shared with four busy
loops, five runs, none force-stopped, 175 to 209 s each; unpinned on sandcastle
at load 23, 21.9 s.

Judgement call: 200 MB, since a trial run with 300 MB still had a worker
force-stopped.

Model: opus-5-5

Implements the decision in https://git.eeqj.de/sneak/AutistMask/pulls/774#issuecomment-177915. No test leaks a handle (https://git.eeqj.de/sneak/AutistMask/issues/766#issuecomment-177603). On a starved CPU, workers holding 380 to 970 MB could not exit within the 500 ms jest allows, and `script/lib/jest.js` failed the run. - `package.json`: `workerIdleMemoryLimit` of `200MB` in the `jest` section. After each test file, a worker whose heap is over 200 MB is replaced by a fresh one. - `tests/jestRunner.test.js` runs `script/lib/jest.js` on `tests/fixtures/leavesIntervalRunning.js`, which leaves an interval running, and expects the force-stop to fail the run. The memory limit makes jest use a worker process even for this one file. `eslint.config.js` gives `tests/fixtures/` the jest globals. - `script/lib/jest.js`, the `Dockerfile` and `README.md` are as on `next`. Measured on `08adee9`: three workers pinned to one core shared with four busy loops, five runs, none force-stopped, 175 to 209 s each; unpinned on sandcastle at load 23, 21.9 s. Judgement call: 200 MB, since a trial run with 300 MB still had a worker force-stopped. Model: opus-5-5
clawbot added the needs-review label 2026-11-11 06:37:14 +01:00
clawbot self-assigned this 2026-11-11 06:37:14 +01:00
Author
Collaborator

FAIL (needs-rework)

  1. package.json, test and test:verbose: in one process the suite takes about 100 seconds in the test stage of the Dockerfile. REPO_POLICIES.md makes 60 seconds a hard cap that fails the suite, and the README's Tests section, which this PR edits, still says the suite must finish within 60 seconds. Acceptable: make test finishes in under 60 seconds. One process cannot do that at the suite's current size, so this needs a new decision on #766 before any rework (for example: keep worker processes and handle their slow exit another way).

  2. script/lib/jest.js, line 21: any stderr write that contains jest's warning text ends the process, including a test's failure message that quotes it. The PR's own tests/jestRunner.test.js does this when one of its stderr assertions fails. Jest prints the received text and the process exits with "a test left a timer or another open handle running", which is false. Later test files never run and no summary prints. Acceptable: only the warning jest itself writes ends the process, as the comment at line 13 ("The start of the warning") already describes. A failure message that quotes the warning is reported like any other failure, and a test covers that case.

  3. Dockerfile: timeout 90 is removed and nothing replaces it. REPO_POLICIES.md requires a time limit above the 60-second cap to catch a hung test. The standing ruling moves CI time limits to the step in the workflow file; it does not drop them. Acceptable: a timeout-minutes on the script/cibuild step in .gitea/workflows/check.yml.

  4. PR body: 283 words, over the 250-word limit. The decision on the issue asked for one line giving run time and peak memory; the body spends a paragraph on figures. Acceptable: under 250 words, the figures in one line, each disclosure in one line.

Model: opus-5-5

FAIL (`needs-rework`) 1. `package.json`, `test` and `test:verbose`: in one process the suite takes about 100 seconds in the `test` stage of the `Dockerfile`. `REPO_POLICIES.md` makes 60 seconds a hard cap that fails the suite, and the README's Tests section, which this PR edits, still says the suite must finish within 60 seconds. Acceptable: `make test` finishes in under 60 seconds. One process cannot do that at the suite's current size, so this needs a new decision on https://git.eeqj.de/sneak/AutistMask/issues/766 before any rework (for example: keep worker processes and handle their slow exit another way). 2. `script/lib/jest.js`, line 21: any stderr write that contains jest's warning text ends the process, including a test's failure message that quotes it. The PR's own `tests/jestRunner.test.js` does this when one of its `stderr` assertions fails. Jest prints the received text and the process exits with "a test left a timer or another open handle running", which is false. Later test files never run and no summary prints. Acceptable: only the warning jest itself writes ends the process, as the comment at line 13 ("The start of the warning") already describes. A failure message that quotes the warning is reported like any other failure, and a test covers that case. 3. `Dockerfile`: `timeout 90` is removed and nothing replaces it. `REPO_POLICIES.md` requires a time limit above the 60-second cap to catch a hung test. The standing ruling moves CI time limits to the step in the workflow file; it does not drop them. Acceptable: a `timeout-minutes` on the `script/cibuild` step in `.gitea/workflows/check.yml`. 4. PR body: 283 words, over the 250-word limit. The decision on the issue asked for one line giving run time and peak memory; the body spends a paragraph on figures. Acceptable: under 250 words, the figures in one line, each disclosure in one line. Model: opus-5-5
Author
Collaborator

For the reworker. New decision on #766, replacing the one-process plan: finding 1 is right, REPO_POLICIES.md caps make test at 60 seconds and one process takes about 100. The rest of the review falls with that plan.

  1. Revert the PR to next for package.json (--maxWorkers=3 stays), script/lib/jest.js (a force-stop still fails the run), the Dockerfile (timeout 90 stays: REPO_POLICIES.md asks for a 90-second backstop on the test command) and the README Tests section.
  2. Keep worker processes, and make them exit fast. The earlier finding was that exit time grows with what a worker holds (380 to 970 MB at the end). Set jest's workerIdleMemoryLimit in the jest section of package.json, so that a worker that has grown past the limit after a test file is replaced by a fresh one. Pick the limit by measurement.
  3. If that does not meet step 4, try workerThreads: true instead. If neither meets it, stop, say so on the issue with what you measured, and open no PR.
  4. Pass criteria, measured with the setup from #766 (comment) (three workers pinned to one core shared with four busy loops): five runs, none force-stopped. On an idle host the suite stays under 60 seconds.
  5. Keep the test with the fixture that leaves an interval running, now expecting the force-stop failure from script/lib/jest.js, so a real leak still fails the run.
  6. PR body under 250 words; the measured figures in one line.

Model: opus-5-5

For the reworker. New decision on https://git.eeqj.de/sneak/AutistMask/issues/766, replacing the one-process plan: finding 1 is right, `REPO_POLICIES.md` caps `make test` at 60 seconds and one process takes about 100. The rest of the review falls with that plan. 1. Revert the PR to `next` for `package.json` (`--maxWorkers=3` stays), `script/lib/jest.js` (a force-stop still fails the run), the `Dockerfile` (`timeout 90` stays: `REPO_POLICIES.md` asks for a 90-second backstop on the test command) and the README Tests section. 2. Keep worker processes, and make them exit fast. The earlier finding was that exit time grows with what a worker holds (380 to 970 MB at the end). Set jest's `workerIdleMemoryLimit` in the `jest` section of `package.json`, so that a worker that has grown past the limit after a test file is replaced by a fresh one. Pick the limit by measurement. 3. If that does not meet step 4, try `workerThreads: true` instead. If neither meets it, stop, say so on the issue with what you measured, and open no PR. 4. Pass criteria, measured with the setup from https://git.eeqj.de/sneak/AutistMask/issues/766#issuecomment-177603 (three workers pinned to one core shared with four busy loops): five runs, none force-stopped. On an idle host the suite stays under 60 seconds. 5. Keep the test with the fixture that leaves an interval running, now expecting the force-stop failure from `script/lib/jest.js`, so a real leak still fails the run. 6. PR body under 250 words; the measured figures in one line. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-11-11 07:30:58 +01:00
clawbot added 1 commit 2026-11-11 08:11:20 +01:00
test: replace jest workers past 200 MB so they exit in time (closes #766)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run
08adee9b01
On a starved CPU, jest force-stopped worker processes that could not exit
within the 500 ms it allows, and script/lib/jest.js failed the run although
every test passed. No test leaks a handle; exit time grows with what a
worker holds, 380 to 970 MB at the end of the run.

workerIdleMemoryLimit in package.json replaces a worker whose heap is over
200 MB after a test file with a fresh one.

tests/jestRunner.test.js runs script/lib/jest.js on a fixture that leaves
an interval running and expects the force-stop to fail the run.

Model: opus-5-5
clawbot force-pushed issue-766-run-tests-in-band from 4cb61d1a10 to 08adee9b01 2026-11-11 08:11:20 +01:00 Compare
clawbot changed title from test: run jest in one process, fail on an open handle (closes #766) to test: replace jest workers past 200 MB so they exit in time (closes #766) 2026-11-11 08:36:50 +01:00
clawbot added needs-review and removed needs-rework labels 2026-11-11 08:36:50 +01:00
Author
Collaborator
  1. Done. README.md is reverted whole: its script/test line also describes the timeout 90 that stays.
  2. Done: 200MB. A trial run with 300MB still had a worker force-stopped.
  3. Not needed.
  4. Met on 08adee9: five pinned runs, none force-stopped; unpinned at load 23, 21.9 s.
  5. Done. The memory limit makes jest run the single fixture file in a worker, so the leak is force-stopped and fails the run.
  6. Done.

Model: opus-5-5

1. Done. `README.md` is reverted whole: its `script/test` line also describes the `timeout 90` that stays. 2. Done: `200MB`. A trial run with `300MB` still had a worker force-stopped. 3. Not needed. 4. Met on `08adee9`: five pinned runs, none force-stopped; unpinned at load 23, 21.9 s. 5. Done. The memory limit makes jest run the single fixture file in a worker, so the leak is force-stopped and fails the run. 6. Done. Model: opus-5-5
Author
Collaborator

PASS: ready to squash-merge into next.

Model: opus-5-5

PASS: ready to squash-merge into `next`. Model: opus-5-5
clawbot merged commit 3a8b309d7e into next 2026-11-11 09:37:13 +01:00
clawbot deleted branch issue-766-run-tests-in-band 2026-11-11 09:37:13 +01:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/AutistMask#774