Skip to content

bats shards are balanced by test count, so adding tests can push one bucket past the job ceiling #847

Description

@fujibee

Adding tests to any file re-assigns every shard, so a PR that changes only the test count can move two slow files into one bucket and push that bucket past the job ceiling. This happened on a PR branch, recovered on a re-run, and main has about five minutes of headroom, so it can happen again to whoever adds tests next.

Recording the measurements first. The conclusion is deliberately left open.

What was measured

1. The buckets are a function of the head, so a shard number is not a stable name for a piece of work.

.github/scripts/shard-tests.sh partitions *.bats by test count (greedy LPT). Derived with that script on each head, for the two slowest files:

head test_remote_sync.bats test_sqlite_sync_jq_binary.bats
4c448cb195aafd7991b373847797154403419fae (main) shard 2/4 shard 1/4 — split
87d91e1a208b3d3c3a7725b6693b857bef104345 (a PR branch) shard 2/4 shard 2/4 — together

The branch adds fifteen test cases to one file (test_roster_journal.bats, which lands in shard 3/4 on that head). That is the whole input change: nothing about the two files above is touched.

2. The bucket that got both of them exceeded the ceiling, and then did not.

duration outcome
branch, bats (macos-latest 2/4), attempt 1 25m22s cancelled at the job ceiling
branch, bats (macos-latest 2/4), attempt 2 23m37s success

The cancelled attempt reported its last test ok twelve seconds before the cancellation, so it was still running normally when the ceiling arrived — not stuck.

3. main is already close to the ceiling.

macOS shards on main at 121d27bb9e7f1c2af8fb0813e90359209691b408's predecessor run:

11m05s  1/4
 9m15s  2/4
20m02s  3/4      <- about five minutes of headroom
11m33s  4/4

And on the branch: 11m21s / 25m22s / 10m48s / 14m05s.

What follows, and what does not

  • Not established: that the added cases are themselves expensive enough to matter. They are in a different shard, which finished in 10m48s. Their own runtime is not the cost.
  • Established: the changed test count moved the partition, and the partition put the two slowest files together.
  • Established: balancing by count does not bound duration. Nothing in the current scheme notices that one file takes twenty minutes and another takes twenty seconds.

So the trigger is any PR that changes how many tests exist — which is most of them.

Candidates, not a decision

Listing these separately because picking between them needs measurement this issue does not have:

  1. Weight the partition by recorded duration rather than by test count. Needs a source of timings and a decision about where they live.
  2. Pin the known slow files apart, as an explicit rule rather than as an accident of counting.
  3. Raise the job ceiling. Cheapest, and it does not stop the buckets from drifting further apart.

A useful first step for any of them is publishing per-shard durations alongside the file list each run, so the next occurrence is measurable rather than reconstructed.

Reproducing the derivation

bash .github/scripts/shard-tests.sh <n> 4      # on each head, for n in 1..4

Comparing shard numbers across heads without deriving the membership will mislead: the same number denotes different files on different commits.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions