mirror of
https://github.com/simstudioai/sim.git
synced 2026-10-16 14:50:06 +08:00
fix(ci): unblock @next/swc, lockfile-keyed node_modules, per-image runner sizing (#5945)
* fix(ci): key node_modules sticky disk on the lockfile hash * improvement(ci): per-image Blacksmith runner sizing + cold-build memory preflight * fix(deps): exclude @next/swc binaries from the release-age gate * fix(deps): pin @next/swc binaries so frozen installs get a compiler * docs(ci): explain ARM runner sizing rationale
This commit is contained in:
@@ -104,7 +104,7 @@ jobs:
|
||||
name: Build Dev ECR
|
||||
needs: [detect-version, migrate-dev]
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/dev'
|
||||
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-8vcpu-ubuntu-2404' || matrix.gh_runner }}
|
||||
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && matrix.bs_runner || matrix.gh_runner }}
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -115,18 +115,25 @@ jobs:
|
||||
include:
|
||||
# Only the app image needs the paid 8-core/32 GB runner: next build
|
||||
# exhausts the free 16 GB one (exit 137). The others build in <5 min.
|
||||
# bs_runner mirrors that per-image sizing on Blacksmith — a single
|
||||
# pinned tier put every image on 8 vCPU, where the non-app builds idle
|
||||
# at 12-15% CPU and under 10% memory.
|
||||
- dockerfile: ./docker/app.Dockerfile
|
||||
ecr_repo_secret: ECR_APP
|
||||
gh_runner: linux-x64-8-core
|
||||
bs_runner: blacksmith-8vcpu-ubuntu-2404
|
||||
- dockerfile: ./docker/db.Dockerfile
|
||||
ecr_repo_secret: ECR_MIGRATIONS
|
||||
gh_runner: ubuntu-latest
|
||||
bs_runner: blacksmith-2vcpu-ubuntu-2404
|
||||
- dockerfile: ./docker/realtime.Dockerfile
|
||||
ecr_repo_secret: ECR_REALTIME
|
||||
gh_runner: ubuntu-latest
|
||||
bs_runner: blacksmith-4vcpu-ubuntu-2404
|
||||
- dockerfile: ./docker/pii.Dockerfile
|
||||
ecr_repo_secret: ECR_PII
|
||||
gh_runner: ubuntu-latest
|
||||
bs_runner: blacksmith-4vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
@@ -215,7 +222,7 @@ jobs:
|
||||
if: >-
|
||||
github.event_name == 'push' &&
|
||||
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging')
|
||||
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-8vcpu-ubuntu-2404' || matrix.gh_runner }}
|
||||
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && matrix.bs_runner || matrix.gh_runner }}
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -229,18 +236,22 @@ jobs:
|
||||
ghcr_image: ghcr.io/simstudioai/simstudio
|
||||
ecr_repo_secret: ECR_APP
|
||||
gh_runner: linux-x64-8-core
|
||||
bs_runner: blacksmith-8vcpu-ubuntu-2404
|
||||
- dockerfile: ./docker/db.Dockerfile
|
||||
ghcr_image: ghcr.io/simstudioai/migrations
|
||||
ecr_repo_secret: ECR_MIGRATIONS
|
||||
gh_runner: ubuntu-latest
|
||||
bs_runner: blacksmith-2vcpu-ubuntu-2404
|
||||
- dockerfile: ./docker/realtime.Dockerfile
|
||||
ghcr_image: ghcr.io/simstudioai/realtime
|
||||
ecr_repo_secret: ECR_REALTIME
|
||||
gh_runner: ubuntu-latest
|
||||
bs_runner: blacksmith-4vcpu-ubuntu-2404
|
||||
- dockerfile: ./docker/pii.Dockerfile
|
||||
ghcr_image: ghcr.io/simstudioai/pii
|
||||
ecr_repo_secret: ECR_PII
|
||||
gh_runner: ubuntu-latest
|
||||
bs_runner: blacksmith-4vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
@@ -387,7 +398,7 @@ jobs:
|
||||
# never moves a documented tag.
|
||||
build-ghcr-arm64:
|
||||
name: Build ARM64 (GHCR Only)
|
||||
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-8vcpu-ubuntu-2404-arm' || matrix.gh_runner }}
|
||||
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && matrix.bs_runner || matrix.gh_runner }}
|
||||
timeout-minutes: 30
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
permissions:
|
||||
@@ -396,19 +407,27 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Non-app images sit at 4 vCPU rather than the finer x64 split: the ARM
|
||||
# sizing data is job-level (8 -> 4 for the whole matrix), not per-image,
|
||||
# and this job only runs on push to main — an unprovisioned label would
|
||||
# hang a release in `queued` rather than fail a PR.
|
||||
include:
|
||||
- dockerfile: ./docker/app.Dockerfile
|
||||
image: ghcr.io/simstudioai/simstudio
|
||||
gh_runner: linux-arm64-8-core
|
||||
bs_runner: blacksmith-8vcpu-ubuntu-2404-arm
|
||||
- dockerfile: ./docker/db.Dockerfile
|
||||
image: ghcr.io/simstudioai/migrations
|
||||
gh_runner: ubuntu-24.04-arm
|
||||
bs_runner: blacksmith-4vcpu-ubuntu-2404-arm
|
||||
- dockerfile: ./docker/realtime.Dockerfile
|
||||
image: ghcr.io/simstudioai/realtime
|
||||
gh_runner: ubuntu-24.04-arm
|
||||
bs_runner: blacksmith-4vcpu-ubuntu-2404-arm
|
||||
- dockerfile: ./docker/pii.Dockerfile
|
||||
image: ghcr.io/simstudioai/pii
|
||||
gh_runner: ubuntu-24.04-arm
|
||||
bs_runner: blacksmith-4vcpu-ubuntu-2404-arm
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
|
||||
@@ -10,7 +10,8 @@ permissions:
|
||||
jobs:
|
||||
process-docs-embeddings:
|
||||
name: Process Documentation Embeddings
|
||||
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-latest' }}
|
||||
# Network-bound on the embeddings API: ~9% CPU and ~3% peak memory on 8 vCPU.
|
||||
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-2vcpu-ubuntu-2404' || 'ubuntu-latest' }}
|
||||
timeout-minutes: 30
|
||||
if: github.ref == 'refs/heads/main'
|
||||
|
||||
|
||||
@@ -31,6 +31,13 @@ jobs:
|
||||
# namespace on top: untrusted fork runs must never share a cache with
|
||||
# push runs (whose caches feed production image builds) or with trusted
|
||||
# internal-PR runs.
|
||||
#
|
||||
# node_modules also keys on the lockfile hash: a sticky disk is a mutable
|
||||
# volume, and `bun install --frozen-lockfile` adds what the lockfile needs
|
||||
# without pruning what it dropped, so branches on different lockfiles were
|
||||
# contaminating each other (a stale @next/swc 16.2.6 outlived the 16.2.11
|
||||
# bump). The bun and Turbo caches are content/hash-addressed, so they stay
|
||||
# shared — that is what keeps a fresh node_modules disk cheap to fill.
|
||||
- name: Mount Bun cache
|
||||
uses: ./.github/actions/cache-mount
|
||||
with:
|
||||
@@ -42,7 +49,7 @@ jobs:
|
||||
uses: ./.github/actions/cache-mount
|
||||
with:
|
||||
provider: ${{ vars.CI_PROVIDER }}
|
||||
key: ${{ github.repository }}-node-modules-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}
|
||||
key: ${{ github.repository }}-node-modules-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-${{ hashFiles('bun.lock') }}
|
||||
path: ./node_modules
|
||||
|
||||
- name: Mount Turbo cache
|
||||
@@ -193,19 +200,16 @@ jobs:
|
||||
# Next.js production build, in parallel with lint + tests. Sticky disks are
|
||||
# cloned from the last committed snapshot per job and committed last-writer-
|
||||
# wins, so concurrent mounts are safe. The bun/node_modules disks are shared
|
||||
# with test-build (identical content from the same lockfile — LWW loss is
|
||||
# harmless), but the Turbo cache gets its own key: with a shared key, only
|
||||
# the last committer's new entries survive each run, so the test and build
|
||||
# Turbo entries would evict each other nondeterministically.
|
||||
# Same next build as the app image, so it needs a large runner. Peak RSS
|
||||
# tracks Turbo/Turbopack cache warmth, and it is the COLD case that sizes the
|
||||
# runner: warm peaks ~12 GB, partial ~28 GB, and a cold full rebuild peaked
|
||||
# 51 GB. The 8vcpu tier only has 30.4 GB, so cold-cache runs OOM-killed the VM
|
||||
# (oom_count 1, memory p100 ~30.5 GB, ~99% of the tier) — the job burned 8-15
|
||||
# min and died, while warm runs finished under 8 min. NODE_OPTIONS'
|
||||
# --max-old-space-size only caps Node's JS heap; the bulk is native Turbopack
|
||||
# worker memory, so the cap cannot prevent this. 16vcpu = 60.8 GB fits the
|
||||
# 51 GB cold peak with headroom. Keep the test job on 8vcpu; its memory is fine.
|
||||
# with test-build (the lockfile-hashed key means they only ever share when the
|
||||
# dependency tree really is identical, so LWW loss is harmless), but the Turbo
|
||||
# cache gets its own key: with a shared key, only the last committer's new
|
||||
# entries survive each run, so the test and build Turbo entries would evict
|
||||
# each other nondeterministically.
|
||||
#
|
||||
# Runner is sized for the COLD-cache build, which is what OOM-killed the 8vcpu
|
||||
# tier (23 kills / 1074 runs at 98% of its 30.4 GB): warm peaks ~12 GB, cold
|
||||
# peaked 51 GB. NODE_OPTIONS' --max-old-space-size caps only Node's JS heap,
|
||||
# not the native Turbopack workers that dominate, so it cannot prevent this.
|
||||
build:
|
||||
name: Build App
|
||||
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-16vcpu-ubuntu-2404' || 'linux-x64-8-core' }}
|
||||
@@ -236,7 +240,7 @@ jobs:
|
||||
uses: ./.github/actions/cache-mount
|
||||
with:
|
||||
provider: ${{ vars.CI_PROVIDER }}
|
||||
key: ${{ github.repository }}-node-modules-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}
|
||||
key: ${{ github.repository }}-node-modules-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-${{ hashFiles('bun.lock') }}
|
||||
path: ./node_modules
|
||||
|
||||
- name: Mount Turbo cache
|
||||
@@ -258,6 +262,21 @@ jobs:
|
||||
key: ${{ github.repository }}-nextjs-cache-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}
|
||||
path: ./apps/sim/.next/cache
|
||||
|
||||
# Running out of RAM kills the whole VM and surfaces only as "the runner
|
||||
# has received a shutdown signal" — no mention of memory, ~12 min in. Warn
|
||||
# with the real numbers so that failure is a one-line diagnosis instead of
|
||||
# a mystery. Warn, never fail: a warm build peaks ~12 GB and a partial one
|
||||
# ~28 GB, so a 32 GB runner still completes plenty of builds, and the
|
||||
# GitHub fallback is the break-glass path — degrading it to a guaranteed
|
||||
# failure would be worse than the risk this flags.
|
||||
- name: Check runner memory headroom
|
||||
run: |
|
||||
TOTAL_GB=$(awk '/MemTotal/ {printf "%d", $2/1048576}' /proc/meminfo)
|
||||
echo "Runner memory: ${TOTAL_GB} GB"
|
||||
if [ "$TOTAL_GB" -lt 40 ]; then
|
||||
echo "::warning::Runner has ${TOTAL_GB} GB. A cold-cache build peaks ~51 GB, so this run may be OOM-killed (reported only as 'the runner has received a shutdown signal'). Warm/partial builds should still fit."
|
||||
fi
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
"turbo": "2.9.14",
|
||||
"yaml": "^2.8.1",
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "16.2.11",
|
||||
"@next/swc-darwin-x64": "16.2.11",
|
||||
"@next/swc-linux-arm64-gnu": "16.2.11",
|
||||
"@next/swc-linux-x64-gnu": "16.2.11",
|
||||
},
|
||||
},
|
||||
"apps/docs": {
|
||||
"name": "docs",
|
||||
@@ -1230,6 +1236,14 @@
|
||||
|
||||
"@next/env": ["@next/env@16.2.11", "", {}, "sha512-0do5A3BJ2gxWr0ZCMcD6BhW+e595jyxdTl3rXTS6lOtD8ektMiW6CO+EPwt1Eca1DBnm90r/7GdiKWBKxH++DA=="],
|
||||
|
||||
"@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.2.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wryL4pjKmDwGv2ox6+GZDFxvmtSRLqApBR8kL1j4+vhB7Z5vJC/zAnXpiR9Xkfzl0AS8WLMnsuGV/UKI67/rrw=="],
|
||||
|
||||
"@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.2.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-aZl2j4f/fLyjQvOhv0Oe9UaMAQHolYpKhctsoYzplSumKJKPUmgjcf6545aBtysLTcu994TREd0+pSgNE4ohmg=="],
|
||||
|
||||
"@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.2.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-5jEriyEnH/LWFy27L2ZG0XaLlyEJIjhsImEsiS9P563PKEVp2BVups/xfOucIrsvVntp11oNcZwjHvaDPYVB5g=="],
|
||||
|
||||
"@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.2.11", "", { "os": "linux", "cpu": "x64" }, "sha512-8WgzpaWMs46qJT9kiV47cje86L0x/Mu9t8/Gwj+pnbgW3rETVfCnaScPjlYUwNScpOozdcIMHWmAvuZJUonR2w=="],
|
||||
|
||||
"@noble/ciphers": ["@noble/ciphers@2.2.0", "", {}, "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA=="],
|
||||
|
||||
"@noble/hashes": ["@noble/hashes@2.2.0", "", {}, "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg=="],
|
||||
|
||||
+12
-4
@@ -7,10 +7,14 @@ minimumReleaseAge = 604800
|
||||
# dev builds, so every version is structurally younger than any age gate.
|
||||
# The exactly pinned Pi 0.80.10 packages were vetted for the cloud-review SDK
|
||||
# migration; they age out of the gate on 2026-07-24 — drop these four entries then.
|
||||
# next@16.2.11 and @next/env@16.2.11 are the official Vercel security patch for the
|
||||
# July 2026 advisories (SSRF, cache confusion, DoS, middleware bypass — GHSA-89xv-2m56-2m9x
|
||||
# et al.); published 2026-07-21, they age out of the gate on 2026-07-28 — drop these two
|
||||
# entries then.
|
||||
# next@16.2.11, @next/env@16.2.11 and the @next/swc-* binaries are the official Vercel
|
||||
# security patch for the July 2026 advisories (SSRF, cache confusion, DoS, middleware
|
||||
# bypass — GHSA-89xv-2m56-2m9x et al.); published 2026-07-21, they age out of the gate on
|
||||
# 2026-07-28 — drop these entries then. The swc binaries ship in lockstep with next and
|
||||
# MUST be excluded alongside it: they are next's platform-gated optionalDependencies, so
|
||||
# gating them out leaves them absent from bun.lock entirely, and `bun install
|
||||
# --frozen-lockfile` then installs no compiler at all — next falls back to downloading one
|
||||
# at build time, which fails in CI.
|
||||
# @anthropic-ai/sdk is exactly pinned to 0.114.0, vetted for the agent-events
|
||||
# streaming work (adaptive thinking display types + transform-json-schema);
|
||||
# published 2026-07-23, it ages out of the gate on 2026-07-30 — drop this entry then.
|
||||
@@ -22,6 +26,10 @@ minimumReleaseAgeExcludes = [
|
||||
"@earendil-works/pi-tui",
|
||||
"next",
|
||||
"@next/env",
|
||||
"@next/swc-darwin-arm64",
|
||||
"@next/swc-darwin-x64",
|
||||
"@next/swc-linux-arm64-gnu",
|
||||
"@next/swc-linux-x64-gnu",
|
||||
"@anthropic-ai/sdk",
|
||||
]
|
||||
|
||||
|
||||
@@ -73,6 +73,12 @@
|
||||
"mermaid": "11.15.0",
|
||||
"zod": "4.3.6"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "16.2.11",
|
||||
"@next/swc-darwin-x64": "16.2.11",
|
||||
"@next/swc-linux-arm64-gnu": "16.2.11",
|
||||
"@next/swc-linux-x64-gnu": "16.2.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.0.0-beta.5",
|
||||
"@octokit/rest": "^21.0.0",
|
||||
|
||||
Reference in New Issue
Block a user