Move the two docker build jobs off the small runner lane
#508
Closed
opened 2026-07-20 22:23:32 +02:00 by timothy
·
2 comments
No Branch/Tag Specified
main
renovate/lucene.net
renovate/dotnet-monorepo
renovate/sqlitepclraw.bundle_e_sqlite3-3.x
renovate/meziantou.analyzer-3.x
renovate/cliwrap-3.x
913-scripted-playout-401
release/v26.15.0-notes
issue-806-guard-populations
scratch/767b-poisoned
scratch/767b-control
release/v26.14.0-notes
release/v26.14.0
docs/510-skill-logo-bug-policy
fix/510-watermark-resolution-policy
fix/629-verdict-classifier-falseopens
fix/609-decisions-edit-token-scope
issue-135-clear-to-none
release/v26.12.0-notes
fix/409b-lastscan-api-parity
fix/401-updatechannel-mirror-422
fix/327-playlist-rename-validation
fix/410-scancancel-log-level
fix/409-447-librariesscreen-neverscanned
fix/338-zap-exit-code
fix/367-plex-budget-message
fix/310-debom-legacy-cs
ci/604-lane-rebalance
feat/388-design-mirror
feat/247-test-ownership
feat/247-primary-action
feat/357-player-owned-playback
feat/357-jellyfin-plugin-poc
fix/289-mcp-hardening
issue58-mcp
feat/244-channels-extract
ci/auto-bump-prod-compose
feat/multi-rerun-collections-api
feat/collections-api
feat/quick-wins
feat/185-docs-part2
feat/140-collections-screen
feat/146-channel-edit
feat/147-classic-ui-link
issue22-renovate-dashboard
feat/91-cutover
feat/63-composite-create
feat/65-library-browse
feat/85-epg
feat/86-schedule-editor
feat/109-dashboard-data
feat/99-session-tracking
fix/dockerfile-node-tag
feat/59-spa-foundation
docs/59-ui-redesign-brief
feat/102-json-guide
feat/111-schedule-durations
feat/104-artwork-upload
feat/103-media-sources-api
feat/playouts-read-api
feat/108-health-api
feat/105-picker-list-endpoints
issue-97-channel-state-api
issue42-jellyfin-musicvideos
issue46-rest-api-error-contract
dependabot/nuget/ErsatzTV.FFmpeg.Tests/multi-d307a2e06f
qsv-improvements
hdr-vulkan-cuda-test
v26.16.0
v26.15.0
v26.14.0
v26.13.0
v26.12.0
v26.11.0
v26.10.0
v26.9.0
v26.8.0
v26.7.0
blazor-final
v26.6.0
v26.5.0
v26.4.0
v26.3.1
v26.3.0
v26.2.0
v26.1.1
v26.1.0
v25.9.0
v25.8.0
v25.7.1
v25.7.0
v25.6.0
v25.5.0
v25.4.0
v25.3.1
v25.3.0
v25.2.0
v25.1.0
v0.8.8-beta
v0.8.7-beta
v0.8.6-beta
v0.8.5-beta
v0.8.4-beta
v0.8.3-beta
v0.8.2-beta
v0.8.1-beta
v0.8.0-beta
v0.7.9-beta
v0.7.8-beta
v0.7.7-beta
v0.7.6-beta
v0.7.5-beta
v0.7.4-beta
v0.7.3-beta
v0.7.2-beta
v0.7.1-beta
v0.7.0-beta
v0.6.9-beta
v0.6.8-beta
v0.6.7-beta
v0.6.6-beta
v0.6.5-beta
v0.6.4-beta
v0.6.3-beta
v0.6.2-beta
v0.6.1-beta
v0.6.0-beta
v0.5.8-beta
v0.5.7-beta
v0.5.6-beta
v0.5.5-beta
v0.5.4-beta
v0.5.3-beta
v0.5.2-beta
v0.5.1-beta
v0.5.0-beta
v0.4.5-alpha
v0.4.4-alpha
v0.4.3-alpha
v0.4.2-alpha
v0.4.1-alpha
v0.4.0-alpha
v0.3.8-alpha
v0.3.7-alpha
develop
v0.3.6-alpha
v0.3.5-alpha
v0.3.4-alpha
v0.3.3-alpha
v0.3.2-alpha
v0.3.1-alpha
v0.3.0-alpha
v0.2.5-alpha
v0.2.4-alpha
v0.2.3-alpha
v0.2.2-alpha
v0.2.1-alpha
v0.2.0-alpha
v0.1.5-alpha
v0.1.4-alpha
v0.1.3-alpha
v0.1.2-alpha
v0.1.1-alpha
v0.1.0-alpha
v0.0.62-alpha
v0.0.61-alpha
v0.0.60-alpha
v0.0.59-alpha
v0.0.58-alpha
v0.0.57-alpha
v0.0.56-alpha
v0.0.55-alpha
v0.0.54-alpha
v0.0.53-alpha
v0.0.52-alpha
v0.0.51-alpha
v0.0.50-alpha
v0.0.49-prealpha
v0.0.48-prealpha
v0.0.47-prealpha
v0.0.46-prealpha
v0.0.45-prealpha
v0.0.44-prealpha
v0.0.43-prealpha
v0.0.42-prealpha
v0.0.41-prealpha
v0.0.40-prealpha
v0.0.39-prealpha
v0.0.38-prealpha
v0.0.37-prealpha
v0.0.36-prealpha
v0.0.35-prealpha
v0.0.34-prealpha
v0.0.33-prealpha
v0.0.32-prealpha
v0.0.31-prealpha
v0.0.30-prealpha
v0.0.29-prealpha
v0.0.28-prealpha
v0.0.27-prealpha
v0.0.26-prealpha
v0.0.25-prealpha
v0.0.24-prealpha
v0.0.23-prealpha
v0.0.22-prealpha
v0.0.21-prealpha
v0.0.20-prealpha
v0.0.19-prealpha
v0.0.18-prealpha
v0.0.17-prealpha
v0.0.16-prealpha
v0.0.15-prealpha
v0.0.14-prealpha
v0.0.13-prealpha
v0.0.12-prealpha
v0.0.11-prealpha
v0.0.10-prealpha
v0.0.9-prealpha
v0.0.8-prealpha
v0.0.7-prealpha
v0.0.6-prealpha
v0.0.5-prealpha
v0.0.4-prealpha
v0.0.3-prealpha
v0.0.2-prealpha
v0.0.1-prealpha
Labels
Clear labels
ad-hoc
api
bug
ci-cd
content
dependencies
enhancement
frontend
in-progress
jellyfin
parked
priority: high
priority: low
priority: medium
review
security
One-off / ad-hoc work not tracked by a dedicated issue
REST API / HTTP endpoints
Something isn't working
Build, test, deploy pipeline
Channel content / schedules / playlists
Dependency updates (Renovate)
New feature or improvement
ChicoryTV React SPA frontend
Claimed by an active session — do not pick up
Jellyfin tuner / IPTV integration
Excluded from automatic queue pickup; work only when explicitly selected
Adversarial review finding
Security / vulnerability fix
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: timothy/ersatztv#508
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
runs-on: smallcurrently carries two jobs that are not small:docker-build.yml→build(Build & push image) — a real buildx on main/tag pushes.ci-image.yml→build(Build & push CI image) — a full buildx of the .NET toolchain image. It reads as lightweight because it is "docker-only, no toolchain needed — it builds the toolchain", but it is the heaviest job in the lane.A lane's per-job memory cap is set by its worst member, so these two pinned
smallat--memory=10g. On bumblebee's 25 GiB (also the prod media host) that permits exactly one slot — and four jobs shared it.The visible symptom is not queue wait. A dispatched job wedges in act's setup phase: >10 min
in_progress, no log file written at all (OpenLogs … .log.zst: file does not exist), then failure, before Checkout runs. That is the origin of the "decisions.mdappend-only is a known flake, just rerun it" folklore — the rerun only works because it lands after load clears. See server-management#639 for the evidence (run 910 / internal 1179).Change
Move both
buildjobs toruns-on: ubuntu-latest.smallthen holds only git-only jobs (decisions-guard,ci-image-pin,docs-reminder), so server-management can cap it at 1 GiB and widen it to 4 slots across two hosts — committing less RAM to CI than the single 10 GiB slot did.server-management#639 owns the runner-side half (bumblebee retune + a new capped runner on jazz).
Why this doesn't re-create #574
#574 moved
buildtosmallbecause Gitea dispatches a job as a runner task even when itsifskips it, and that skip-task queued ~31 min behind long builds. It cannot recur:buildhasneeds: [test, migrations], so it is not dispatched until the jobs it would queue behind have already finished.ci-image.yml's build has noneedsbut triggers only ondocker/ci/**pushes and a weekly cron.Done-when
buildjobs areruns-on: ubuntu-latestdocs/ci-cd.mdrunner/lane section reflects the four-runner topology and the git-only rule forsmalldocs/decisions.mdentry recorded (append-only)Status — PR #509, one flaky-red away from mergeable
Diff done & reviewed. Both heavy jobs (
docker-build.yml's imagebuild+ci-image.yml's toolchainbuild) are onubuntu-latest;smallis now git-only (ci-image-pin,docs-reminder,decisions-guard); docs updated (ci-cd.mdfour-runner table + git-only rule;decisions.mdentry). Cold adversarial review passed —Review-verdict: MERGEABLE @ 5709bf5aon the PR. 4/5 Done-when boxes ticked.Why there are two commits. Editing
ci-image.ymlmakes theci-image-pinguard require the pin to point at the newly-published toolchain image — commit4263cf7(stale pin) failed that guard on run 917, and5709bf5abumped all pins to4263cf7(guard green on run 918). Verified: 1 distinct pin, resolves to the guard'sexpected, image present in the registry.The only red is an unrelated CI-capacity flake.
Build & test (.NET)on run 918 failed a single SPA test (LibrariesScreen.test.tsx:292,waitFortimeout). It cannot be caused by this diff (CI-config + docs only, 0 lines of app/SPA code). Root cause is a starved CI VM — run summary showsenvironment 49.30s/import 16.42s, ~200× the local ~0.2s — amplified because this PR's ownci-image.ymledit triggered a concurrent 2 GB toolchain rebuild (run 917) on the sameubuntu-latestlane. Locally: 3/3 for that test, 889/889 full suite. Every other run-918 job passed (EF migrations included).Action needed (operator). I can't clear this from the agent side: a push would re-trigger the ci-image rebuild and re-amplify the load, and PR-job rerun/cancel is UI-only on Gitea 1.25.4. Please re-run just
Build & test (.NET)on run 918 from the Actions UI once the superseded run 917 drains — same pattern as thedecisions.md-flake rerun. It should land green (no new ci-image rebuild, lane no longer double-loaded), which ticks the last Done-when box and lets the H6/H10 gate auto-grant the merge.Follow-up worth filing:
LibrariesScreen.test.tsx's scan-complete test still depends on real-microtask timing under awaitForbudget, which is what makes it CI-load-flaky despite prior hardening — a candidate for a deterministic rewrite (drive the poll chain's promises to completion rather than racing them).Closed — merged as
64414be1(PR #509)What was done. Both heavy
buildjobs moved offruns-on: small→ubuntu-latest:docker-build.yml's image push andci-image.yml's toolchain buildx.smallis now git-only (ci-image-pin,docs-reminder,decisions-guard), so server-management#639 can cap it at 1 GiB and widen it to 4 slots across two hosts. #574's skip-task queueing can't recur becausebuildkeepsneeds: [test, migrations].Files changed.
.gitea/workflows/docker-build.yml,.gitea/workflows/ci-image.yml,docs/ci-cd.md(four-runner table + git-only rule),docs/decisions.md(append-only entry). Two commits: the lane move (4263cf7) + a required CI-image pin bump (5709bf5a).Why the pin bump was necessary (root cause of the two-commit shape). Editing
ci-image.ymlre-publishes the toolchain image at that commit's sha and makes theci-image-pinguard require the pin to match it — so4263cf7alone failedci-image-pinon run 917, and5709bf5abumped all six pins to4263cf7(guard green on run 918). This is inherent guard behavior, not a defect.CI. Run 918 went green after a single
Build & test (.NET)rerun. The first attempt failed one flaky SPA test (LibrariesScreen.test.tsx:292) purely from CI-VM starvation (environment 49.30svs ~0.2s local), amplified by the concurrent toolchain rebuild this PR's ownci-image.ymledit triggered on the same lane — unrelated to the diff (0 lines of app/SPA code; 889/889 local). The rerun (no new rebuild, undivided lane) passed.Deferred / follow-up. Filed a low-priority issue to make that scan-complete SPA test deterministic (it still races real microtasks under a
waitForbudget). Note that #508 + server-management#639 attack that flake's root cause (lane starvation), so its frequency should drop regardless.Docs updated.
docs/ci-cd.md+docs/decisions.mdin-PR (both required by the change). No operational Obsidian/MEMORY change needed — this is CI-lane topology already captured inci-cd.md.