mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-20 14:12:59 +03:00
fix(build): raise Node heap for local next build to stop OOM/stall (#4171)
Integrated into release/v3.8.29 — raise Node heap for local next build (extends #4104 Docker OOM fix to the native path). Validated: 10/10 tests, typecheck:core, file-size, test-discovery, eslint green.
This commit is contained in:
committed by
GitHub
parent
aaa740f7fd
commit
771f1cfac9
@@ -107,16 +107,32 @@ export function resolveNextBuildBundlerFlag(baseEnv = process.env) {
|
||||
}
|
||||
|
||||
export function resolveNextBuildEnv(baseEnv = process.env) {
|
||||
return {
|
||||
const env = {
|
||||
...baseEnv,
|
||||
NEXT_PRIVATE_BUILD_WORKER: baseEnv.NEXT_PRIVATE_BUILD_WORKER || "0",
|
||||
};
|
||||
|
||||
// Raise the Node heap for the spawned `next build`. The webpack production pass
|
||||
// ("Compiling instrumentation" bundles the whole server graph) is the heaviest
|
||||
// phase and overflows V8's default ~2 GB ceiling on memory-constrained machines,
|
||||
// stalling/OOMing local `npm run build` (npm-global installs). #4076/#4104 fixed
|
||||
// this only in the Docker builder stage (ENV NODE_OPTIONS); the local/native path
|
||||
// was left unprotected. Respect an existing --max-old-space-size (Docker already
|
||||
// sets one — don't clobber/duplicate) and let OMNIROUTE_BUILD_MEMORY_MB override.
|
||||
if (!/--max-old-space-size/.test(env.NODE_OPTIONS || "")) {
|
||||
const heapMb = Number(baseEnv.OMNIROUTE_BUILD_MEMORY_MB) || 4096;
|
||||
env.NODE_OPTIONS = `${env.NODE_OPTIONS || ""} --max-old-space-size=${heapMb}`.trim();
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
async function resetStandaloneOutput(rootDir = projectRoot, fsImpl = fs) {
|
||||
// Use the module-level distDir so NEXT_DIST_DIR is respected
|
||||
const resolvedDistDir =
|
||||
rootDir === projectRoot ? distDir : path.join(rootDir, process.env.NEXT_DIST_DIR || ".build/next");
|
||||
rootDir === projectRoot
|
||||
? distDir
|
||||
: path.join(rootDir, process.env.NEXT_DIST_DIR || ".build/next");
|
||||
const standaloneRoot = path.join(resolvedDistDir, "standalone");
|
||||
if (!(await exists(standaloneRoot))) return;
|
||||
|
||||
@@ -128,7 +144,9 @@ async function resetStandaloneOutput(rootDir = projectRoot, fsImpl = fs) {
|
||||
|
||||
export async function pruneStandaloneArtifacts(rootDir = projectRoot, fsImpl = fs) {
|
||||
const resolvedDistDirForPrune =
|
||||
rootDir === projectRoot ? distDir : path.join(rootDir, process.env.NEXT_DIST_DIR || ".build/next");
|
||||
rootDir === projectRoot
|
||||
? distDir
|
||||
: path.join(rootDir, process.env.NEXT_DIST_DIR || ".build/next");
|
||||
const standaloneRoot = path.join(resolvedDistDirForPrune, "standalone");
|
||||
const pruneTargets = [path.join(standaloneRoot, "_tasks")];
|
||||
|
||||
@@ -174,11 +192,9 @@ export async function main() {
|
||||
const standaloneDir = path.join(distDir, "standalone");
|
||||
if (result.code === 0 && (await exists(standaloneDir))) {
|
||||
try {
|
||||
await fs.cp(
|
||||
path.join(projectRoot, "docs"),
|
||||
path.join(standaloneDir, "docs"),
|
||||
{ recursive: true }
|
||||
);
|
||||
await fs.cp(path.join(projectRoot, "docs"), path.join(standaloneDir, "docs"), {
|
||||
recursive: true,
|
||||
});
|
||||
console.log("[build-next-isolated] Copied docs/ to standalone output");
|
||||
} catch (docsCopyErr) {
|
||||
console.warn("[build-next-isolated] Non-fatal error copying docs/:", docsCopyErr?.message);
|
||||
@@ -194,7 +210,9 @@ export async function main() {
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("[build-next-isolated] Assembling standalone bundle (static + public + natives + extras)...");
|
||||
console.log(
|
||||
"[build-next-isolated] Assembling standalone bundle (static + public + natives + extras)..."
|
||||
);
|
||||
assembleStandalone({
|
||||
distDir,
|
||||
outDir: standaloneDir,
|
||||
@@ -202,10 +220,7 @@ export async function main() {
|
||||
copyNatives: true,
|
||||
});
|
||||
} catch (assembleErr) {
|
||||
console.warn(
|
||||
"[build-next-isolated] Non-fatal error assembling standalone:",
|
||||
assembleErr
|
||||
);
|
||||
console.warn("[build-next-isolated] Non-fatal error assembling standalone:", assembleErr);
|
||||
}
|
||||
}
|
||||
process.exitCode = result.code;
|
||||
|
||||
@@ -107,6 +107,36 @@ test("resolveNextBuildEnv forces stable build worker mode unless already provide
|
||||
assert.equal(preservedEnv.NODE_ENV, "production");
|
||||
});
|
||||
|
||||
// Escalated bug (WhatsApp BR, cmqiuhd7600): a local `npm run build` stalls/OOMs
|
||||
// during the webpack production pass ("Compiling instrumentation" bundles the whole
|
||||
// server graph). #4076/#4104 raised the heap only in the Docker builder stage; the
|
||||
// local/native path (build-next-isolated.mjs → resolveNextBuildEnv) was left on V8's
|
||||
// default ~2 GB ceiling, so memory-constrained npm-global installs hit the same OOM.
|
||||
test("resolveNextBuildEnv raises the Node heap for memory-constrained local builds", () => {
|
||||
const env = resolveNextBuildEnv({ NODE_ENV: "production" });
|
||||
const match = (env.NODE_OPTIONS ?? "").match(/--max-old-space-size=(\d+)/);
|
||||
assert.ok(
|
||||
match,
|
||||
"local build must set NODE_OPTIONS --max-old-space-size to avoid the webpack-pass OOM"
|
||||
);
|
||||
assert.ok(
|
||||
Number(match[1]) >= 4096,
|
||||
`build heap default must be >= 4096 MB (the V8 default ~2 GB OOMed); got ${match[1]}`
|
||||
);
|
||||
});
|
||||
|
||||
test("resolveNextBuildEnv does not clobber an existing --max-old-space-size (Docker)", () => {
|
||||
const env = resolveNextBuildEnv({ NODE_OPTIONS: "--max-old-space-size=8192" });
|
||||
const occurrences = (env.NODE_OPTIONS.match(/--max-old-space-size=/g) || []).length;
|
||||
assert.equal(occurrences, 1, "must not duplicate the heap flag when one is already set");
|
||||
assert.match(env.NODE_OPTIONS, /--max-old-space-size=8192/);
|
||||
});
|
||||
|
||||
test("resolveNextBuildEnv honors the OMNIROUTE_BUILD_MEMORY_MB override", () => {
|
||||
const env = resolveNextBuildEnv({ OMNIROUTE_BUILD_MEMORY_MB: "6144" });
|
||||
assert.match(env.NODE_OPTIONS, /--max-old-space-size=6144/);
|
||||
});
|
||||
|
||||
test("getTransientBuildPaths leaves _tasks in place by default", () => {
|
||||
const paths = getTransientBuildPaths("/repo", {});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user