CI downloads 174 MB before it runs a single test #115
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The
testjob installs its dependencies with a fullpacman -Syuonarchlinux:latestat the start of every run — currently 174 MB of downloads, all of it beforeactions/checkouthas even run. The runner shares this host's internet connection, so whenever that connection is busy the job dies during package retrieval witherror: failed retrieving file ... Operation too slow. Less than 1 bytes/sec transferred the last 10 seconds, having executed none of the code it was meant to test.Three of the last five runs on PR #114 failed this way (136 and 138 failed, 137 passed with identical dependency needs) — the outcome tracks link conditions, not the diff. Measured during the failures: ~84–175 KB/s from three different Arch mirrors, with the host's uplink saturated at ~5 MB/s by seeding, which starves downstream ACKs. Related but distinct from the DNS-starvation flake already recorded for this runner.
CI is disabled for now (
on: workflow_dispatchonly) so PRs stop collecting red Xs for reasons unrelated to their contents. Re-enable as part of fixing this.Options, roughly best-first:
runs-onthat image. Per-run download drops to ~zero, and the job stops being hostage to the connection. Costs a rebuild step when dependencies change, which is rare and explicit.:latest, so-Syuhas less to reconcile. Helps a little, and pins the tested platform, which is arguably worth having on its own.Worth deciding alongside: the job tests against a rolling
:latestArch, so an upstream breakage and a real regression currently look identical.Correction: the download size wasn't the cause
The diagnosis above blames the ~174MB of package downloads. That framing is wrong in a way worth recording, because it made "shrink the download" look like the fix when the actual problem was elsewhere.
174MB is about two seconds on this link. The runs failed because the downlink collapsed to 84–175 KB/s — a ~99.98% degradation — and that is ordinary bufferbloat from a saturated uplink starving ACKs. Anything sharing the connection was affected; CI was just the thing that reported it as a red X.
Measured from 30d of container counters:
The upload distribution sits flat on its own maximum, which is a hard cap rather than a workload tail. Both directions cross the same tunnel, so the VPN isn't the constraint — the WAN link is simply that asymmetric. Nothing on the host can absorb it either:
enp5s0has fq_codel, but it drains at 1 Gbps into the switch so its queue never builds. The buffer that fills is in the ISP modem, downstream of anything we control.What was actually saturating it: a
share_limitsgroup in qbit_manage that had matched nothing since it was written. It required both thenoHLandPublictags, but an imported release keeps its library hardlink for life, sonoHLnever arrives and the group sat atTorrents (0)run after run without erroring. Public torrents therefore had no share limit at all — 33 of them, seeding up to 83 days each, pinning the uplink at a sustained ~4.5 MB/s. Fixed by dropping the hardlink gate; upload fell to 0.18 MB/s.What shipped here
The CI change stands on its own merits regardless of link state, so it was done anyway — but as an efficiency and reproducibility fix, not as the remedy for the failures.
Of the three options above, the second turned out to be the strongest once combined with the third. Package caching was dismissed as only "narrowing the window", but that assumed
:lateststayed. Pinning the base image and pointing pacman at a frozenarchive.archlinux.orgsnapshot closes it: versions can't move underneath the cache, so a run downloads nothing but the repo databases.dependsarray rather than thepython-subset, so CI exercises what an install actually getspush/pull_requesttriggers restoredBaking a prebuilt image was considered and rejected: every path to building one needed privileges worth more than the problem. The Dagu socket proxy withholds
POST /builddeliberately, and building in CI would have meant granting jobs Docker access permanently — which Forgejo's own docs note has no security isolation — to avoid a weekly task that needs it once.Verified in the pinned container before merge: 274 passed, ruff and compileall clean. Run 139 on trunk added nothing to the package cache, confirming it was served entirely from it.