Repository navigation
refactor: scalable runner slots, job-safe cache budgets, slim/ndk images, leaner CI (+ upstream sync) - #31
Merged
Merged
Conversation
Update SDK/JDK versions
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Adds <runner>-jdkNN-sdkNN-ndkX.Y.Z next to the existing tag so downstream repos that pin an Android NDK (Gradle ndkVersion) can have Renovate derive it from the image tag and bump image and NDK together. The weekly SDK/NDK automation already rewrites ARG NDK_VERSION, so the tag follows it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
deploy: also tag images with the NDK version they ship
…-tools Stable platforms since android-37.0 carry an empty <codename></codename> in Google's repository manifest, so is_preview() skipped every 37.x and the image stayed on platform 36.1. Only a non-empty codename marks a preview now. deploy also publishes <runner>-jdkNN-sdkX.Y-btX.Y.Z-ndkX.Y.Z so consumers can let Renovate derive compileSdk, buildToolsVersion and ndkVersion from the image pin; the existing -sdk-ndk tag is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d-bt-tag SDK check: treat an empty <codename> as stable; tag images with build-tools
Update SDK/JDK versions
… detection, bt/ndk image tags) Brings in upstream d79fa65: SDK bump to 37.2, empty <codename> treated as stable in check-sdk-updates, deploy tags images with NDK and build-tools versions (suffixed with -node<N> to keep the fork's node variants distinct), README tag examples. Dockerfile/deploy.yml/README customizations of the fork are preserved. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
azlekov
marked this pull request as ready for review
October 19, 2026 17:23
…hat never prunes a busy slot - a store table + one lru_entries engine replace the three bespoke LRU functions; whole entries where partial ones break builds - bounds all 13 slot stores (was 5): bun, npm, pnpm, gradle, cargo, rustup, konan, mise, hk, pub, hosted tool cache (#7) - gradle evicts whole dependency versions, transforms and wrapper dists, never single files (#17) - host budget = min(CACHE_BUDGET_BYTES, CACHE_BUDGET_PCT of the data disk), split across slots, global LRU within a slot - skips slots marked busy (fresh marker) under the slot's .prune.lock; early pass and tighter docker prune when disk is low - tests for bun, gradle, cargo, pnpm, rustup, toolcache, busy slots and the budget split Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…path work dirs, per-host sizing - one runner service scaled by RUNNERS (+ CONTROL_RUNNERS) replaces 3 hand-copied services and 36 named volumes - each container flock-claims RUNNER_DATA_DIR/slots/<id> for its lifetime; work dir and caches live in the slot - the data dir is mounted at the same host path, so docker run -v, container actions and container: jobs see the checkout (#19) - default cache paths (bun, npm, pnpm, gradle, cargo, rustup, konan, mise, hk, pub, hostedtoolcache) link into the slot (#8) - pre-job marks the slot busy and sweeps leftovers only after a crashed job; cleanup clears busy and wipes /tmp flat - optional RUNNER_CPUS / RUNNER_MEMORY; under a CPU quota gradle/cargo/make/cmake workers are capped to it - hosts/sizing.sh suggests RUNNERS, limits, the pruner budget and :slim on arm64; RUNNER_CACHES=off replaces no-caches overlay - tests/slots.sh: concurrent claims, labels, links, parallelism, hooks and a store-list drift guard Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
azlekov
force-pushed
the
feat/runner-slots
branch
from
October 19, 2026 18:04
61b8c31 to
032f062
Compare
…xxd and rustup - sdk stage runs sdkmanager on a fixed JDK, so the SDK layer is identical for every JDK/Node tag - core: base + one apt layer (xxd, pigz) + rustup-init + JDK + Node; runner-slim = core without the Android SDK - android = core + SDK on top: the weekly SDK bump replaces only that layer; runner (default, last) and runner-ndk build on it - NDK and cmake move to the opt-in runner-ndk target: default image 5.65 -> 3.18 GiB, slim 2.58 GiB on arm64 (#17) - runtime scripts come from a scratch stage copied last, so script edits never invalidate the SDK/NDK layers - rustup without a toolchain; the preflight sets it up per slot so toolchains persist in the slot cache Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… App-token SDK update PRs - JDK 17, 21, 25, 27 x Node 22, 24: deploy 20 builds + 10 merges (was 32 + 16) incl. slim and ndk, PR 8 legs (was 11) - type=gha layer cache scoped per platform/variant, timeout-minutes, zstd-compressed layers (#15, #17) - slim and ndk tags; upstream's build-tools / NDK-version tags kept, NDK ones on the ndk variant only - tests/image-smoke.sh runs on the PR's amd64 std/slim/ndk legs; shellcheck covers every script; compose config validated - check-sdk-updates opens and auto-merges PRs with the org App token (APP_ID / APP_PRIVATE_KEY secrets) so CI runs (#17) - drops non-LTS JDKs once a newer GA lands Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s, maintenance and troubleshooting Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
azlekov
force-pushed
the
feat/runner-slots
branch
from
October 19, 2026 18:12
032f062 to
bf28ace
Compare
azlekov
added this pull request to stack #34
October 19, 2026 19:54
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One PR for the runner refactor. It simplifies the setup, adapts it to each host, and keeps caches healthy on every machine in the fleet: Raspberry Pi 5, Hetzner and beelink-class hosts. It merges the 10 upstream compscidr commits, plus four work packages built in parallel sessions.
Closes #7
Closes #8
Closes #15
Closes #16
Closes #17
Closes #19
It prepares for #18 (emulator):
hosts/sizing.shreports/dev/kvm, and the emulator itself is a follow-up.What changed
Runtime topology (W3)
runnerservice scaled byRUNNERS(plusCONTROL_RUNNERS) replaces three hand-copied services and 36 named volumes.flock-claimsRUNNER_DATA_DIR/slots/<id>for its lifetime. The work dir and all caches live in the slot, and the tools' default paths symlink into it.docker run -v "$PWD:…", container actions andcontainer:jobs see the checkout (Container actions and docker run -v get empty mounts: runner work dir must be mounted at the same host path #19). Verified from inside a runner container.RUNNER_CPUS/RUNNER_MEMORYper runner. Under a CPU quota the preflight caps Gradle (org.gradle.workers.max), cargo, make and cmake parallelism.hosts/sizing.sh light|largesuggestsRUNNERS, limits, the cache budget, and:slimon arm64.pre-job.shmarks the slotbusy, waiting on the pruner's lock first.cleanup.shclearsbusyand wipes/tmpflat; the recursive spare-the-workdir walk is gone.Pruner (W4)
lru_entriesengine and a store table replace three bespoke functions. It evicts whole entries wherever partial ones break builds: bun packages, Gradle versions, rustup toolchains, toolcache versions, the pnpm store, and so on.min(CACHE_BUDGET_BYTES, CACHE_BUDGET_PCT), is split across slots, with global LRU within a slot.PRUNE_FREE_PCT.CI (W2)
type=ghalayer cache scoped per platform,timeout-minutes, and zstd-compressed layers.slim/ndktags. An image smoke test runs on PRs.docker compose configis validated.check-sdk-updatesopens PRs with the org App token (needsAPP_ID/APP_PRIVATE_KEYrepo secrets) and auto-merges. Non-LTS JDKs are dropped when a newer GA lands.Image (W1)
sdk(fixed JDK, so the SDK layer is identical for every tag),core(base, one apt layer incl.xxd/pigz, JDK, Node, hooks), thenrunner-slim= core,android= core + SDK,runner-ndk= android + NDK/cmake, andrunner= android (the last, default stage).rustupwithout a toolchain: the image ships a checksum-verifiedrustup-init, and the preflight sets rustup up in each slot's~/.cargo. Toolchains a job installs persist in the slot (stable --profile minimal: 7 s cold, 0 s warm).android-37.xis stable (empty<codename/>); the old preview filter skipped it. Upstream's fix and the 37.2 bump come in through the sync.Upstream sync
<codename>-is-stable SDK detection, and build-tools / NDK spelled-out tags.ndkvariant, the only one that ships an NDK.Docs
Commits
chore: merge upstream compscidr/main. This is a real merge, so later upstream syncs don't re-conflict.refactor(pruner): the store-table engine, per-slot budgets, and busy-slot safety.feat(compose): scalable slots, identical-path work dirs, sizing, and the job hooks.feat(image): the slim, default and ndk targets, the shared SDK layer,xxdand rustup.ci: the matrix, the layer cache, variants, the smoke test, and App-token SDK PRs.docs(readme).Figures
RUNNERS=N)slim+ndkslim/ndksmoke legs, all layer-cacheddocker run -v/ container actions on self-hostedndk5.42 GiB opt-inslim: 2.81 GiB amd64 / 2.58 GiB arm64, no Android SDKBaselines were measured over 1,068 self-hosted jobs in 6 onboarded repos, about 1,900 jobs a week fleet-wide. Image sizes are from local amd64/arm64 builds; all three targets pass
tests/image-smoke.sh.What the onboarded repos get
server-onlyeviction break. npm and pnpm are bounded, and container actions work.rustupis ready, and toolchains stay warm per runner.slimimage and a cache budget that scales with the disk.Upgrading a host (breaking)
COMPOSE_PROFILES=controlandhosts/no-caches.compose.ymlare replaced byCONTROL_RUNNERSandRUNNER_CACHES=off.Verification
tests/*.shpass inubuntu:24.04: slots, pruner budget, busy slots, and bun, cargo, gradle, pnpm, rustup and toolcache eviction.docker compose configpasses forRUNNERS=1/3/5.RUNNERS=2, plus a control runner) checked that:.env;busy;--cpus 1.5.runner,runner-slim(amd64 + arm64) andrunner-ndkwere built and smoke-tested locally.Follow-ups (other repos)
dodi-smart/.github: lift the container-action ban inAGENTS.md.setup-stack: drop the job-scopedPUB_CACHEand the ARM64$RUNNER_TEMPcache isolation.stacks.md: fix the "caches are job-scoped" line.🤖 Generated with Claude Code