test: run release v2 QA from shared standalone build

This commit is contained in:
ajnart committed 2026-09-01 06:23:19 +02:00
1 parent b40468f37c
commit a149dbdfab
9 files changed
+266 -91

No files matched your search

+3 -3
View File
@@ -36,7 +36,7 @@ pnpm qa:release-v2:runtime -- status --slot 1
pnpm qa:release-v2:runtime -- stop --slot 1
```
Slots `1`, `2`, and `3` have separate database files, Redis containers and ports, cookie prefixes, logs, fixture ports, app ports, and `.next-qa/slot-<n>` build directories. The runtime manifest is written only after the app is ready and records the watcher interval. Status checks the owned processes, app, fixture, and Redis. Stop is idempotent for a stopped manifest and refuses to signal a live PID that does not carry the recorded QA run ID.
Slots `1`, `2`, and `3` have separate database files, Redis containers and ports, cookie prefixes, logs, fixture ports, and app ports. They reuse one immutable candidate-pinned production standalone build under `.next-qa/release-v2-<candidate-sha>`, so three active profiles do not each retain a multi-gigabyte development compiler. The runtime manifest is written only after the standalone app is ready and records the exact shared build and server path. Status checks the owned processes, app, fixture, and Redis. Stop is idempotent for a stopped manifest and refuses to signal a live PID that does not carry the recorded QA run ID.
Every start, reset, and stop holds an exclusive per-slot filesystem lease outside the resettable slot tree. A second operation on the same slot fails deterministically. Stale recovery compares both the recorded PID and its operating-system process-start marker; it never signals a lease owner or an unrelated process. An incomplete fresh lease is preserved for a short grace period instead of being guessed stale.
@@ -44,9 +44,9 @@ The fixture child receives an explicit environment allowlist containing only its
The selected app port remains bound by a temporary loopback reservation through migration and seeding. The reservation is released immediately before Next.js binds. If another process wins that unavoidable release-to-bind window and Next.js reports `EADDRINUSE`, startup retries with a newly reserved, dynamically selected port. No application port is hard-coded.
`--reset` is intentionally narrow: after validating the QA run-root marker, it stops only the selected running manifest, removes only that slot directory, and clears only that slot's `.next-qa` cache. The run root must be a direct child of the canonical operating-system temporary directory returned by Node, its basename must be `homarr-release-v2-qa` or start with `homarr-release-v2-qa-`, and only safe suffix characters are accepted. Temporary-directory aliases are canonicalized before containment checks. Existing run roots and slot paths must not be symlinks or contain symlink components, and destructive paths are rechecked immediately before mutation. The Linux default `/tmp/homarr-release-v2-qa` remains unchanged.
`--reset` is intentionally narrow: after validating the QA run-root marker, it stops only the selected running manifest, removes only that slot directory, and clears only the selected slot's legacy development cache. It never removes the shared candidate build while another slot may use it. The run root must be a direct child of the canonical operating-system temporary directory returned by Node, its basename must be `homarr-release-v2-qa` or start with `homarr-release-v2-qa-`, and only safe suffix characters are accepted. Temporary-directory aliases are canonicalized before containment checks. Existing run roots and slot paths must not be symlinks or contain symlink components, and destructive paths are rechecked immediately before mutation. The Linux default `/tmp/homarr-release-v2-qa` remains unchanged.
This host's `fs.inotify.max_user_instances=128` is too low for concurrent native Watchpack watchers. Spawned QA apps use Next.js Webpack development mode (`--webpack`) and set `WATCHPACK_POLLING=1000`, avoiding reliance on another inotify instance while keeping all three isolated slots available. Webpack also gives clean browser sessions a deterministic development chunk graph instead of retaining stale Turbopack chunk URLs. Filesystem changes can take up to one polling interval to reach HMR. The runtime manifest records `bundler: "webpack"`, and live verification rejects another bundler. Existing slots must be restarted before they satisfy this contract.
This host's `fs.inotify.max_user_instances=128` is too low for concurrent development watchers, and three Webpack development compilers exceed the available memory. The runtime therefore creates one candidate-pinned production standalone build with `next build --webpack` and reuses it across the three isolated slots. The shared build has no watcher or HMR surface, eliminating stale development chunks and keeping each running app lightweight. Source changes require a commit and a new candidate build before browser evidence is valid. Provision slots sequentially when the shared build does not exist yet; once it is present, all three may run concurrently. The runtime manifest records `runtimeMode: "production-standalone"`, `bundler: "webpack"`, `watcher: null`, and the exact build metadata; live verification rejects another contract. Existing development slots must be restarted before they satisfy it.
## Profiles