From d792be839b439096d619928b6c8587e60f1143bd Mon Sep 17 00:00:00 2001 From: Vyncint Ng Date: Mon, 7 Sep 2026 13:42:00 +0700 Subject: [PATCH] fix(release): link the three binaries one at a time in binaries.yml Every Linux binary job of the last two releases died at the same point, linking oxidelake-runtime after all 444 dependencies had compiled, with "The runner has received a shutdown signal" and exit code 143: v0.1.0 (both musl targets) and v0.1.2 (aarch64 musl). The release profile is fat LTO with a single codegen unit, so each binary's link is a whole-program LLVM pass over Arrow, DataFusion and Ballista, and Cargo schedules the three binaries' links in parallel. Three of those exceed a 16 GB Linux runner with no swap and the VM is torn down. macOS survives by swapping, which is why its jobs took four hours on v0.1.0. `cargo install` from crates.io is unaffected because a crate built outside the workspace does not carry the workspace release profile, which is why the install job passes while the binaries job dies. Build the binaries with one `cargo build --bin` per binary: the dependencies still compile in parallel during the first invocation, and the second and third only link, so one LTO pass is in memory at a time. A re-run against an existing tag now checks the release first and skips targets whose archive is already attached instead of rebuilding them, so `gh workflow run binaries.yml --ref main -f tag=vX.Y.Z` fills in the missing Linux archives for v0.1.2 without repeating the macOS builds. Not done: no automated test covers the workflow shell; the skip step was dry-run locally against v0.1.0, v0.1.2 and a nonexistent tag, and the link change is verified by the dispatched run for v0.1.2. Signed-off-by: Vyncint Ng --- .github/workflows/binaries.yml | 40 ++++++++++++++++++++++++++++++++-- CHANGELOG.md | 9 ++++++++ docs/RELEASING.md | 3 ++- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index bc03a58..8fee20e 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -66,18 +66,53 @@ jobs: with: persist-credentials: false ref: ${{ env.TAG }} + # A re-run against an existing tag (docs/RELEASING.md) must not rebuild + # what is already published: an archive is immutable once uploaded, and + # a macOS build of this graph is measured in hours. + - name: Already on the release? + id: published + env: + GH_TOKEN: ${{ github.token }} + TARGET: ${{ matrix.target }} + run: | + set -euo pipefail + archive="oxidelake-${TAG#v}-${TARGET}.tar.gz" + assets="$(gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json assets --jq '.assets[].name' 2>/dev/null || true)" + if printf '%s\n' "$assets" | grep -qxF "$archive"; then + echo "$archive is already attached to $TAG — nothing to build" + echo "present=true" >> "$GITHUB_OUTPUT" + else + echo "present=false" >> "$GITHUB_OUTPUT" + fi - name: Add the target's standard library + if: steps.published.outputs.present != 'true' env: TARGET: ${{ matrix.target }} run: rustup target add "$TARGET" - name: musl linker (Linux) - if: contains(matrix.target, 'musl') + if: steps.published.outputs.present != 'true' && contains(matrix.target, 'musl') run: sudo apt-get update -q && sudo apt-get install -y -q musl-tools + # One binary per invocation, on purpose. The release profile is fat LTO + # with a single codegen unit, so linking a binary is a whole-program LLVM + # pass over Arrow, DataFusion and Ballista. Cargo schedules the three + # binaries' links in parallel, and three of those do not fit in a 16 GB + # Linux runner that has no swap: the VM is torn down and the job ends + # with "The runner has received a shutdown signal", exit 143, at exactly + # this point — v0.1.0 (both musl targets) and v0.1.2 (aarch64 musl). + # macOS survives only by swapping, which is where its hours go. The + # dependencies still compile in parallel during the first invocation; + # the second and third only link. - name: Build + if: steps.published.outputs.present != 'true' env: TARGET: ${{ matrix.target }} - run: cargo build --release --locked -p oxidelake-runtime --target "$TARGET" + run: | + set -euo pipefail + for binary in oxide oxide-scheduler oxide-worker; do + cargo build --release --locked -p oxidelake-runtime --bin "$binary" --target "$TARGET" + done - name: Package + if: steps.published.outputs.present != 'true' env: TARGET: ${{ matrix.target }} run: | @@ -113,6 +148,7 @@ jobs: # Uploaded only if absent, never clobbered: a published archive is # immutable, and rebuilding a tag yields a different checksum. - name: Attach to the release + if: steps.published.outputs.present != 'true' env: GH_TOKEN: ${{ github.token }} run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index a394459..32e42d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,15 @@ versions (0.x) may contain breaking changes; they are always listed under a ## [Unreleased] +### Fixed + +- **Linux release binaries build again.** `binaries.yml` links the three + binaries one at a time: the release profile's fat LTO made Cargo run three + whole-program links in parallel, which exhausted the 16 GB Linux runners + and ended every musl job with exit 143 (v0.1.0 and v0.1.2 both shipped + without Linux archives). A re-run against an existing tag now skips targets + whose archive is already attached instead of rebuilding them. + ## [0.1.2] - 2026-09-07 CI and build-gate changes only; no crate code changed since 0.1.1. diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 821901d..c4b1b16 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -26,7 +26,8 @@ Trusted Publishing. checksums; without the secret the job says so and the tap keeps the previous version. To refresh the formula for a tag whose release already ran (or ran from an older workflow): `gh workflow run binaries.yml --ref main -f tag=vX.Y.Z` - — archives already on the release are left alone, only the formula moves. + — targets whose archive is already on the release are skipped without + building, only the missing archives and the formula move. - A **`release` GitHub environment** whose deployment branches are restricted to `v*` tags, so an OIDC publish token can never be minted from a branch. - **`v*` tags protected by a ruleset**, so only a repository admin can create