Skip to content

ci: run the unit and installer tiers on two runners each - #489

Merged
earakely-scale merged 4 commits into
mainfrom
ci/shard-unit-installer-parallel-fast
Nov 4, 2026
Merged

earakely-scale merged 4 commits into
mainfrom
ci/shard-unit-installer-parallel-fast

Conversation

@earakely-scale

@earakely-scale earakely-scale commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

What and why

After #485 the run takes about 12 minutes. The unit and installer tiers don't make use of the runner they're on, and the unit tier's time swings from 8 to 14 minutes.

  • Unit tier. 12.5 min, 8.4 to 14 across runs, for 33.4 worker-minutes of tests: about 8.3 min on 4 workers if packed. No test is long (the slowest is 46 s); with xdist's default scheduling, workers sit idle while the last few queued tests run.
    • Fix: --dist worksteal, which lets an idle worker take queued tests from the others.
    • Split across two runners with AGENTENV_TEST_SHARD, the unit files' times added to the table so the two halves are even (16.7 worker-minutes each).
    • The lockfile and lint checks run on the first shard only.
  • Installer tier. 9.2 min, 36 worker-minutes packed evenly on 4 workers, 33 of them in test_plugin_changes.py.
    • Fix: two runners, with test_plugin_changes.py split by test (31 and 29 of 60 tests).
  • Flaky test fix. The opencode cancel test failed once here with ProcessLookupError, on the very kill it checks for. Reading /proc/<pid>/stat for a process reaped between the open and the read fails with ESRCH. The gemini and claude_code copies of that helper already treat it as gone, and the opencode and hermes copies now do too.
  • Flaky test fix. CodeBuild's run of test_computer_recording.py::test_a_stream_of_frames_keeps_each_frames_capture_time captured 9 frames where it asserts at least 10: it recorded for a fixed 0.8 s at 20 fps. It now also waits, up to 30 s, until the encoder holds 10, so a busy machine records longer instead of failing.

Gate jobs keep the unit and installer check names, so the main ruleset is unaffected. The installer gate also passes when the change touches nothing the tier covers, as the skipped job did before. Every unit and installer shard uploads its JUnit report. .github/scripts/slow_test_durations.py now takes all of a run's junit-* reports, since the table covers four tiers.

Not in this PR: running the fast integration tier in parallel. I tried it, and it exposed a race in run_bundle_test.py's signal test: under load, the signal arrives before the step's command starts. Its 7 to 10 minutes are under the slow tier's anyway, so it stays serial for now.

Job Before This PR's runs
unit 12.5 min (8.4–14) 5.4–7.0 min a shard
installer 9.2 min 4.7–6.4 min a shard

The run's length is now set by the slow tier, about 11.5–13 min. Its image-heavy files (chromium_app_test.py, website_browser_test.py) vary from run to run, and caching those builds is the next step.

How it was tested

  • The table was regenerated from all 18 JUnit reports of the run at ci: rebalance the slow tier and run it on 12 shards, the gateway tests on 5 #485's head. It now has 1,514 units, including the unit tier's 594 files. The installer tier has no report yet, so its tests weigh the same until the next refresh.
  • Collected both unit shards: 6,419 and 6,623 of 13,042 tests, none in both and none missing, 16.7 worker-minutes each by the table.
  • Collected both installer shards: 31 and 29 of 60 tests, none in both and none missing.
  • pytest tst/unit/test_shards.py tst/unit/test_slow_test_durations_script.py: 22 passed. The two fixed test files: 11 passed.
  • This PR's runs: the unit shards took 5.4–7.0 min and the installer shards 4.7–6.4 min.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; no actionable issues were found.

Summary

Splits the unit and installer tiers across two runners while keeping the required check names.

  • Unit tests now run in two parallel runner shards.
  • Installer tests now run in two parallel runner shards.
  • The shard timing table now covers unit and installer tests.
  • Cancellation tests treat a process reaped during a state read as gone.
  • The streamed recording test waits for ten encoded frames.

The change since the previous review only adds the recording wait. No actionable new issues or mounted-rule violations were found. No previous review threads were supplied.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  U1["Unit shard 1"] --> U["unit check"]
  U2["Unit shard 2"] --> U
  C["Changed paths"] --> I1["Installer shard 1"]
  C --> I2["Installer shard 2"]
  I1 --> I["installer check"]
  I2 --> I
  C --> I
  U1 --> J["Separate JUnit reports"]
  U2 --> J
  I1 --> J
  I2 --> J
Loading

Reviews (4) · Last reviewed commit: "test: a streamed recording runs until it..." · Reviewed by Greptile

…t integration tier in parallel

With the slow tier rebalanced, the unit tier became the longest job: 8.4 to 14
minutes for 33 worker-minutes of tests, since xdist's default scheduling leaves
workers idle while the last tests run. It now uses --dist worksteal and runs on
two runners, each about 4 minutes of tests, split by AGENTENV_TEST_SHARD with
the unit files' times added to the table. The lockfile and lint checks run on
the first shard.

The installer tier is 36 worker-minutes, packed evenly on 4 workers, so it runs
on two runners, test_plugin_changes.py split by test. The fast integration tier
ran its 7 minutes of tests one at a time; it runs them with -n auto --dist
loadscope, as make int-test-fast does. Gate jobs keep the unit and installer
check names, and every shard uploads its JUnit report for the next refresh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale
earakely-scale requested a review from a team as a code owner November 4, 2026 18:38
earakely-scale and others added 2 commits November 4, 2026 10:54
… the opencode and hermes kill checks

Reading /proc/<pid>/stat for a process that exits between the open and the read
fails with ESRCH, so the opencode cancel test failed on the kill it was checking
for. The gemini and claude_code copies of this helper already treat
ProcessLookupError as gone; these two now do too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Run in parallel it raced: the signal test sends its signal when the run prints
the step's line, and under load that comes before the step's command starts, so
the command's pid file was never written. The tier's 7 to 10 minutes are under
the slow tier's, so running it serially costs the run nothing for now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale earakely-scale changed the title ci: run the unit and installer tiers on two runners each, and the fast integration tier in parallel ci: run the unit and installer tiers on two runners each Nov 4, 2026
…ed for

The stream test recorded for 0.8 s at 20 fps and asserted at least 10 frames,
which a busy machine missed: CodeBuild captured 9. It now also waits, up to 30 s,
until the encoder holds 10, so a slow machine records longer instead of failing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale
earakely-scale merged commit 75e9613 into main Nov 4, 2026
35 of 36 checks passed
@earakely-scale
earakely-scale deleted the ci/shard-unit-installer-parallel-fast branch November 4, 2026 19:54
earakely-scale added a commit that referenced this pull request Nov 5, 2026
…ions table

main's #489 added its timing after this branch removed the test, so the shard table named a file that is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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