ci: run the gate and the deploys on two runners sized to the CI VPS #574
Open
admin-amaurycoudr
wants to merge 3 commits from
ci/forgejo-runner-sizing into main
pull from: ci/forgejo-runner-sizing
merge into: amaurycoudr:main
amaurycoudr:main
amaurycoudr:docs/contributing-forgejo-ci
amaurycoudr:fix/storybook-ghsa-f2ph-cmg5-wxc8
amaurycoudr:prototype/dead-end-page
amaurycoudr:prototype/puzzles-ui-redesign
amaurycoudr:prototype/399-front-screens
amaurycoudr:ci/front-test-one-job
amaurycoudr:feat/370-drizzle-gateway
amaurycoudr:pr-screenshots
amaurycoudr:feat/369-postgres-per-stack
amaurycoudr:claude/pawn-promotion-capture-score-46fffb
amaurycoudr:claude/github-workflow-improvements-30cf86
amaurycoudr:docs/352-adr-claim-guest
amaurycoudr:docs/351-adr-seat-identity
amaurycoudr:claude/retro-last-10-conversations-9af723
amaurycoudr:docs/accounts-adrs
amaurycoudr:claude/lighthouse-pt-4b5a78
amaurycoudr:docs/350-adr-sessions
amaurycoudr:feat/game-status-326
amaurycoudr:research/postgres-on-vps
amaurycoudr:research/email-provider
amaurycoudr:prototype/offer-overlay
amaurycoudr:ci/339-pr-screenshots
amaurycoudr:prototype/game-status
amaurycoudr:ci/317-faster-pipeline
amaurycoudr:spec/303-vps-hosting
amaurycoudr:claude/paste-invite-link-room-code
amaurycoudr:docs/309-adr-vps-hosting
amaurycoudr:fix/311-client-route-fallback
amaurycoudr:claude/back-navigation-feature-2166ea
amaurycoudr:claude/resource-contract
amaurycoudr:claude/api-nest-orpc
amaurycoudr:claude/adr-nest-orpc
amaurycoudr:claude/e2e-tests-new-features-1ce2a1
amaurycoudr:claude/la-spec-273-fd55ac
amaurycoudr:claude/matt-pocock-skills-integration-444ba9
amaurycoudr:chore/adopt-the-cognitive-load-coding-rules-270
amaurycoudr:feat/choose-the-promotion-piece-in-a-popover-instead-of-auto-queening-267
amaurycoudr:feat/animate-piece-moves-on-the-board-264
amaurycoudr:feat/show-drag-state-on-the-board-263
amaurycoudr:feat/move-a-piece-by-dragging-and-dropping-it-261
amaurycoudr:feat/blocking-modal-when-the-room-has-closed-246
amaurycoudr:feat/truthful-opponent-presence-lost-connection-left-new-opponent-248
amaurycoudr:feat/horizontal-game-and-room-action-bars-with-a-confirmed-leave-247
amaurycoudr:feat/room-status-block-with-a-fixed-height-and-seat-relative-wording-245
amaurycoudr:docs/amend-adr-0016-a-vacated-seat-replaces-the-60-second-left-timer-244
amaurycoudr:feat/lint-against-hard-coded-copy-in-the-front-front-no-literal-copy-252
amaurycoudr:feat/translate-the-front-with-a-language-provider-english-french-242
amaurycoudr:docs/adr-front-i18n-paraglide
amaurycoudr:docs/stacked-prs
amaurycoudr:fix/render-build-fails-on-corepack-enable-record-the-hosting-adr-240
amaurycoudr:front/8-lint-error
amaurycoudr:front/7-local-home-align
amaurycoudr:front/6-comment-purge
amaurycoudr:front/5-cache-policy
amaurycoudr:front/3-dissolve-room-actions
amaurycoudr:front/4-tests-through-view
amaurycoudr:front/2-room-restructure
amaurycoudr:front/1-test-harness
amaurycoudr:feat/deploy-to-render-free-tier-with-a-preview-per-pr-233
amaurycoudr:harness/6-coding-standards
amaurycoudr:harness/5-adrs
amaurycoudr:harness/4-mechanical-rules
amaurycoudr:harness/3-drop-sandcastle
amaurycoudr:harness/2-skill-forks
amaurycoudr:harness/1-adr-index
amaurycoudr:claude/e2e-test-sub-agents-f8d06b
amaurycoudr:claude/e2e-hook-performance-072aa8
amaurycoudr:e2e-restart
amaurycoudr:e2e-spectator
amaurycoudr:e2e-draw-offer
amaurycoudr:e2e-resign-and-reload
amaurycoudr:e2e-mate-two-browsers
amaurycoudr:orchestrate-issue-168-implementation
amaurycoudr:implement-issue-169-and-pr
amaurycoudr:orpc-ws-room-feature
amaurycoudr:home-page-issues
amaurycoudr:comment-audit-and-rules
amaurycoudr:local/4-local-rail
amaurycoudr:local/3-local-board
amaurycoudr:local/2-design-prep
amaurycoudr:local/1-engine-accessors
amaurycoudr:prototype/home-page
amaurycoudr:prototype/game-screen-layout
amaurycoudr:worktree-front
amaurycoudr:chore/worktree-env-and-ports
amaurycoudr:feat/slice-1-3a-front-store-ws-effect-connection-status-screen-136
amaurycoudr:fix/143-release-seat-on-disconnect
amaurycoudr:claude/sandcastle-runner-contract
amaurycoudr:feat/slice-1-2a-apps-api-skeleton-hono-ws-echo-origin-allowlist-132
amaurycoudr:feat/slice-1-1-chess-contracts-package-context-md-cleanup-128
amaurycoudr:refactor/reorganise-src-into-layered-folders-per-adr-0008-123
amaurycoudr:refactor/refactor-engine-reorganise-src-into-layered-folders-per-adr-0008-123
amaurycoudr:refactor/introduce-the-piecereader-read-port-118
amaurycoudr:refactor/move-isattacked-to-attacks-ts-with-board-only-signature-111
amaurycoudr:feat/slice-b1-zobrist-key-computation-for-positions-99
amaurycoudr:refactor/slice-a-re-back-squareset-with-split-32-representation-97
amaurycoudr:sandcastle/sequential-reviewer/1779180017269
amaurycoudr:feat/san-formatter-core-encoding-moves-captures-en-passant-promotion-castling-92
amaurycoudr:sandcastle/sequential-reviewer/1779111400188
amaurycoudr:refactor/engine-pr-10-1-migrate-stalemate-into-a-draw-status-variant-86
amaurycoudr:sandcastle/sequential-reviewer/1779099667568
amaurycoudr:feat/engine-pr-9-1-castling-rights-tracking-updatecastlingrights-applymove-wiring-80
amaurycoudr:refactor/extract-piece-attacks-registry-and-rewire-isattacked-movegen-77
amaurycoudr:sandcastle/sequential-reviewer/1779027444485
No reviewers
Labels
Clear labels
bug
Something isn't working
documentation
Improvements or additions to documentation
duplicate
This issue or pull request already exists
enhancement
New feature or request
good first issue
Good for newcomers
help wanted
Extra attention is needed
invalid
This doesn't seem right
question
Further information is requested
spec
Parent spec written by to-spec
wayfinder:grilling
wayfinder:map
wayfinder:prototype
wayfinder:research
wayfinder:task
wontfix
This will not be worked on
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
spec
wayfinder:grilling
wayfinder:map
wayfinder:prototype
wayfinder:research
wayfinder:task
wontfix
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set.
Reference
amaurycoudr/chess-project!574
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "ci/forgejo-runner-sizing"
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?
Stacked on #573: merge it first, then rebase this onto
main.Summary
Two runners on the CI VPS (15 GiB, 4 CPUs), each taking one job at a time. ADR 0050 supersedes 0048.
memory.peak3.9 GiB with--maxWorkers=1), so GitLab's 3 GiB was below its working set. That fits run 3's symptoms: 2.999 of 3 GiB, the host swapping, 25 tests timing out and a dynamic import failing.--memory-swapnow equals--memory, so a job at its cap is OOM-killed at once instead of swapping until its tests time out./dev/shmgoes to 2 GiB; it is tmpfs charged to the same cap.--maxWorkers=1. I have no evidence that the MSW cause is not real. GitLab pipeline 315's symptoms (whole files failing, a setup file that would not load) match memory pressure as well as they match MSW. Once a few front-test runs pass at 6 GiB, trying--maxWorkers=2is the next step.TASK_CONCURRENCY=2. checks with a cold Turbo cache took 34 s at concurrency 4 and 36 s at 2, both peaking at 4.3 to 4.5 GiB. Vitest's workers dominate that peak, not Turbo's slots, so the higher setting bought nothing measurable.capacity: 1is the lock. Every job that reaches the production VPS runs ondeploy, so two deploys never overlap. Every browser job runs ondocker, so two browser jobs never share the CPUs. A deploy no longer waits behind a pull request's gate.runner-lanes.test.mjsenforces this: every job runs on a label a runner offers, deploys and browser jobs each stay on one capacity-1 runner, and the caps fit an 8 GiB budget with no swap.actions/cacheis gone from ci.yml and the store sits on theci-pnpm-storevolume at/pnpm-store. GitLab rejected this because pnpm copies across mounts. I measured again: copying costs about 2 s an install, against a restore and a gzip upload on every lockfile change. The numbers are under Evidence.reuse-imageacceptssuccessorskippedfrom them.corepack enableand the Playwright image pull, which is cached anyway. That is a few seconds, not worth an image to rebuild on every Node or Playwright bump. Left as a follow-up.Memory budget, with two jobs running:
After step 12, the 3 GiB GitLab frees stays as page cache and margin.
Evidence
Measured locally in
node:24.21.0-bookwormat--cpus=4, with this repo's lockfile (store 1.3 GB, 40 785 files):actions/cachewithout zstd, which the image lacks)apt install zstdin every jobPeak memory (
memory.peak), same container:--maxWorkers=1: 3.9 GiB, above the old 3 GiB cap.TASK_CONCURRENCY=4and 4.5 GiB at 2, with Vitest seeing the Mac VM's 15 CPUs. On the VPS it sees 4, so the real peak is lower.The local front-test run itself was not a clean signal: Chromium dropped its connection, and the Docker VM had only 7.75 GiB with other stacks using about 3.3 GiB.
Gate:
pnpm lint,typecheck,test(test:infra 59 pass),build,format:checkall green.Merge Danger
Door: two-way
Revert the commit, then rerun stages 3 and 4.
up.shwill then render the single runner again. The deploy runner stays registered in Forgejo until you delete it under Site administration → Actions → Runners.Blast Radius: CI
deployfind no runner and wait. Merging this without applying blocks every deploy, andplan, and so every run. Apply right after merging.reuse-imagewere skipped despite gate jobs that skipped, production would not deploy on a merge. Check the first push to main after this lands.docker buildin the daemon during front-test could slow it. Watch the first runs that overlap.Apply on the server (the owner)
main.up.shrestarts a runner whose config changed, which kills its job.infra/forgejo/vps/wizard.sh. Answer "Redo it?" with yes for stage 3 (copies the stack and the newrunner-deploy.yaml; the secret key and internal token are kept) and stage 4 (up.sh: registersforgejo-vps-deploy-runner, renders both configs, restartsrunner, startsrunner-deploy). Answer no for every other stage.sudo docker compose -f /opt/forgejo/compose.yaml pslistsrunnerandrunner-deployrunning. Check that Site administration → Actions → Runners lists both idle, with labelsdocker,ubuntu-latestanddeploy.sudo grep -E 'capacity|memory|volume' /opt/forgejo/runner/config.yaml /opt/forgejo/runner-deploy/config.yamlshows--memory=6g --memory-swap=6g,ci-pnpm-store, and--memory=2g --memory-swap=2g.These steps are also in
infra/forgejo/vps/README.md, "Apply a change to the runners". The first gate run fillsci-pnpm-store, which takes about 15 s more than a warm install.Order of apply: this pull request's own run needs the deploy runner, since plan now runs on the deploy label. The new runners also serve main's current workflows: the gate runner keeps the docker label and the actions cache. So apply the steps from this branch first (check out ci/forgejo-runner-sizing instead of main in step 1), let this run go green, then merge #573 and this one. Until then, this run waits for a runner.
Run at
f39a5abThe run
Failed tests
No test failed.
front-test failed outside any test it reports; its log says why.
Engine coverage
Statements: 99.48%, shown and never enforced.
Screenshots
No screenshots: no preview was deployed, or capturing it failed.
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.