From c4617265b96dab7332d360303a0a40dbf66ebcc2 Mon Sep 17 00:00:00 2001 From: "mudler's LocalAI [bot]" <139863280+localai-bot@users.noreply.github.com> Date: Thu, 30 Jul 2026 12:17:14 +0200 Subject: [PATCH] fix(ci): trim two pieces of per-PR work that buy nothing (#11219) Measured over the week to 2026-07-30, 97% of CI wall-clock is queueing and 3% is execution: a median 5-hour queue against a 4-20 minute median job. With the queue saturated, throughput is concurrency divided by service time, so cutting execution time raises the drain rate directly. Two steps stood out as paying nothing for what they cost. test.yml: drop the free-disk-space step (~3.1min per run, ~22 h/week). That action exists to make room for docker buildx layers and this job runs no buildx step. It was also sized for a `make test` that downloaded multi-GB GGUF/whisper fixtures and built llama-cpp/whisper/stablediffusion-ggml; the test-suite reorg moved all of that into tests/e2e-backends and tests/e2e-aio, as the Makefile test target already records. Its tool-cache:true wipe was additionally deleting /opt/hostedtoolcache, forcing setup-go and setup-node to re-download toolchains that ship preinstalled on the runner. build-test.yaml: build only the host target on pull_request. The three-platform cross-compile (linux/amd64, linux/arm64, darwin/arm64) is the bulk of that job's ~6.6min median, ~47 h/week, and nothing consumes a PR's binaries. goreleaser's --single-target still runs every before-hook (protogen-go, react-ui, go mod tidy), so the "is the release build broken" signal is unchanged. master pushes and tags keep building all three. Also record why the Linux Go workflows pass cache: false to actions/setup-go, since it reads as an oversight and is not. Set up Go has a median of 11 seconds on those runners, so there is nothing to win, and the repo already sits at GitHub's 10 GB Actions cache ceiling with 31 entries, where each setup-go entry is 222-375 MB on Linux and up to 1.4 GB on macOS. Re-enabling it would evict something that is earning its space. Assisted-by: Claude:opus-5 [claude-code] Signed-off-by: Ettore Di Giacinto Co-authored-by: Ettore Di Giacinto --- .agents/ci-caching.md | 12 +++++++++++- .github/workflows/build-test.yaml | 8 +++++++- .github/workflows/test.yml | 9 +++++++-- Makefile | 9 +++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/.agents/ci-caching.md b/.agents/ci-caching.md index 77b87467e..490bac2d2 100644 --- a/.agents/ci-caching.md +++ b/.agents/ci-caching.md @@ -259,10 +259,20 @@ Eviction is rarely needed in normal operation — `DEPS_REFRESH` handles weekly ## What the cache does **not** cover -- The `free-disk-space` and `setup-build-disk` composite actions run on every job — these reclaim runner-state, not Docker layers, so BuildKit caches don't apply. +- The `free-disk-space` and `setup-build-disk` composite actions run on every job — these reclaim runner-state, not Docker layers, so BuildKit caches don't apply. `test.yml` deliberately does **not** use `free-disk-space`: it runs no buildx step, and the multi-GB fixture downloads that once justified it left `make test` in the test-suite reorg. - Intermediate artifacts of `Build (PR)` are not pushed anywhere — PRs only build for verification. - Darwin builds (see below) — macOS runners have no Docker daemon, so the registry-backed BuildKit cache cannot apply. +### The Linux Go workflows set `cache: false` on purpose + +`test.yml`, `lint.yml`, `tests-e2e.yml` and friends pass `cache: false` to `actions/setup-go@v5`, unlike the darwin jobs. This looks like an oversight and is not. + +Measured over the week to 2026-07-30, the `Set up Go` step has a **median of 11 seconds** on these runners. There is essentially nothing to win: the module download is not where the time goes. The expensive steps are compilation and test execution (`Test (with coverage gate)` at ~18.6min, `Test Backend E2E` at ~14.5min), and Go's build cache would have to survive across runners to touch those. + +Enabling it also has a real cost. GitHub caps Actions cache at **10 GB per repo and the repo already sits at that ceiling** (31 entries), so every `setup-go` entry written by a branch with a distinct `go.sum` (222-375 MB on Linux, up to 1.4 GB on macOS) evicts something else. See the darwin cache budget below. + +Before re-enabling this, measure `Set up Go` again and confirm it has actually become slow. If room is needed in the 10 GB budget, the cheapest evictions are the `docker.io--tonistiigi--binfmt` entries (~30 MB each, trivially re-fetched). + ## Darwin native caches `backend_build_darwin.yml` runs natively on `macOS-14` GitHub-hosted runners — there is no Docker, no BuildKit, no cross-job registry cache. Instead, the reusable workflow uses `actions/cache@v4` for four native caches that mirror the spirit of the Linux cache (warm by default, weekly refresh for unpinned Python deps, PRs read-only). diff --git a/.github/workflows/build-test.yaml b/.github/workflows/build-test.yaml index 23d61d0f5..34b41e09f 100644 --- a/.github/workflows/build-test.yaml +++ b/.github/workflows/build-test.yaml @@ -35,9 +35,15 @@ jobs: uses: actions/setup-go@v5 with: go-version: 1.25 + # A PR builds only the host target. The three-platform cross-compile + # (linux/amd64, linux/arm64, darwin/arm64) is the bulk of this job's + # ~6.6min median and no PR consumes the resulting binaries. The + # before-hooks (protogen-go, react-ui, go mod tidy) run either way, so the + # "is the release build broken" signal is unchanged. master and tags still + # build everything. - name: Run GoReleaser run: | - make dev-dist + make ${{ github.event_name == 'pull_request' && 'dev-dist-single' || 'dev-dist' }} launcher-build-darwin: runs-on: macos-latest steps: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7e702a7dd..7081d630c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,8 +24,13 @@ jobs: uses: actions/checkout@v7 with: submodules: true - - name: Free disk space - uses: ./.github/actions/free-disk-space + # No free-disk-space step here on purpose. That action exists to make room + # for docker buildx layers, and this job runs no buildx step. It was also + # sized for a `make test` that downloaded multi-GB GGUF/whisper fixtures + # and built llama-cpp/whisper/stablediffusion-ggml; after the test-suite + # reorg it does neither (see the Makefile test target). It cost ~3min of + # every run, and its tool-cache:true wipe also forced setup-go and + # setup-node to re-download toolchains that ship preinstalled. - name: Setup Go ${{ matrix.go-version }} uses: actions/setup-go@v5 with: diff --git a/Makefile b/Makefile index af40ee7cf..699c6fd61 100644 --- a/Makefile +++ b/Makefile @@ -172,6 +172,15 @@ build-dev: ## Run LocalAI in dev mode with live reload dev-dist: $(GORELEASER) build --snapshot --clean +## PR-time variant of dev-dist: builds only the host platform instead of all +## three release targets (linux/amd64, linux/arm64, darwin/arm64). The point of +## running goreleaser on a PR is to catch a broken config or a broken +## before-hook (protogen-go, react-ui, go mod tidy), and --single-target still +## exercises every one of those. Nothing consumes a PR's cross-compiled +## binaries. master pushes and tags still run the full dev-dist/dist. +dev-dist-single: + $(GORELEASER) build --snapshot --clean --single-target + dist: $(GORELEASER) build --clean