Skip to content

Stop building the web image's frontend under QEMU - #24

Merged
fylorn merged 1 commit into
mainfrom
hotfix/web-image-native-builder
Sep 15, 2026
Merged

fylorn merged 1 commit into
mainfrom
hotfix/web-image-native-builder

Conversation

@fylorn

@fylorn fylorn commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

What

The main push that merged #23 shows a red ✗: Web Build & Push was cancelled at GitHub's six-hour job limit, so no web image was pushed for 633f641. This PR removes the cause, and caps the job so a hang can't hold a runner that long again.

Why it hung

Dockerfile.web's builder stage ran once per target platform, so the arm64 leg ran pnpm install and pnpm build under QEMU. In run 34862152349, Node crashed 40 seconds into the arm64 install:

#20 39.57 qemu: uncaught target signal 4 (Illegal instruction) - core dumped

The step never exited: the log is silent from 15:32 until the cancellation at 21:31 (UTC). The amd64 leg of the same build had finished in under a minute.

It is not something #23's code does. The crash came mid-download, before any package's own code could run, and the same emulated install succeeded on #22's push.

The fix

  • The builder stage runs on $BUILDPLATFORM. dist/ is static files, identical for every architecture, so it is now built once, natively, and copied into each architecture's nginx image. The nginx stage only copies files, so nothing executes under emulation. It is faster too: on Clear 127 lint findings and gate lint in CI #22's push, emulated pnpm build took 260s against 23s natively.
  • timeout-minutes: 20 on the job. A healthy run takes minutes.
  • A CHANGELOG entry under [Unreleased], following the 1.0.1 entry for the release workflow's move to native runners.

release.yml builds each architecture on its own native runner, where $BUILDPLATFORM already equals the target, so release images are built exactly as before. make docker-build uses plain docker build, which gets $BUILDPLATFORM from BuildKit.

Verification

This job only runs on pushes to main, so this PR's own CI cannot exercise it. I built the image locally for both platforms — docker buildx build --platform linux/amd64,linux/arm64 with a docker-container builder, the kind CI uses, on an arm64 Mac — and exported both images:

  • pnpm build ran exactly once, on the build platform, and both platforms' nginx stages copied its output.
  • Both images contain index.html, their dist/ trees are identical, and each image's nginx binary is its own architecture (x86-64 and aarch64).

The real proof is the next main push, which I will watch.

Left as it is

The Set up QEMU step stays. Nothing in the build needs it any more, but only a main run can show the job works without it, so this PR changes one thing at a time.

🤖 Generated with Claude Code

The Web Build & Push job for 633f641 on main was cancelled at GitHub's
six-hour limit. Dockerfile.web built its builder stage once per target
platform, so the arm64 leg ran `pnpm install` and `pnpm build` under
QEMU. Node crashed there with SIGILL ("qemu: uncaught target signal 4")
40 seconds into the install; the step never exited, and the job sat
idle until GitHub killed it.

dist/ is static files, identical for every architecture. The builder
stage now runs on $BUILDPLATFORM, so it is built once, natively, and
only the COPY-only nginx stage is produced per architecture: nothing
executes under emulation. Emulated, `pnpm build` alone took 260s
against 23s natively.

The job also gets a 20-minute timeout, so a hang fails in minutes
instead of holding a runner for six hours.

release.yml builds each architecture on its own native runner, where
$BUILDPLATFORM already equals the target, so release images are built
exactly as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@fylorn
fylorn merged commit 7a6a93d into main Sep 15, 2026
7 checks passed
@fylorn
fylorn deleted the hotfix/web-image-native-builder branch September 15, 2026 04:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant