mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 20:32:20 +03:00
The Docker image bakes NODE_OPTIONS=--max-old-space-size=256, and the standalone launcher (scripts/dev/run-standalone.mjs, the Docker CMD) spawned 'node server.js' without overriding it — so the server inherited the 256 MB cap and OOMed randomly under load or with a large SQLite DB. `omniroute serve` already honored OMNIROUTE_MEMORY_MB but the Docker path did not. Add a shared resolveMaxOldSpaceMb() helper (OMNIROUTE_MEMORY_MB, default 512, clamped [64,16384]) and have the launcher append --max-old-space-size to the child NODE_OPTIONS (a trailing flag wins, overriding the baked 256 without clobbering other flags). Update the .env.example doc to reflect the 512 default.
74 lines
2.4 KiB
JavaScript
74 lines
2.4 KiB
JavaScript
import { spawn } from "node:child_process";
|
|
|
|
export function parsePort(value, fallback) {
|
|
const parsed = Number.parseInt(String(value), 10);
|
|
return Number.isFinite(parsed) && parsed > 0 && parsed <= 65535 ? parsed : fallback;
|
|
}
|
|
|
|
/**
|
|
* Resolve the V8 heap ceiling (MB) for the server process from
|
|
* `OMNIROUTE_MEMORY_MB`, mirroring `omniroute serve`. Clamped to [64, 16384];
|
|
* invalid/unset → fallback (512). The Docker image bakes
|
|
* NODE_OPTIONS=--max-old-space-size=256, which OOMs under load / large DBs
|
|
* (#2939) — the standalone launcher uses this to override that cap.
|
|
* @param {string | number | undefined | null} value
|
|
* @param {number} [fallback]
|
|
*/
|
|
export function resolveMaxOldSpaceMb(value, fallback = 512) {
|
|
const parsed = Number.parseInt(String(value), 10);
|
|
return Number.isFinite(parsed) && parsed >= 64 && parsed <= 16384 ? parsed : fallback;
|
|
}
|
|
|
|
/**
|
|
* @param {NodeJS.ProcessEnv | Record<string, string | undefined>} [fromEnv]
|
|
* Defaults to process.env. Pass bootstrap `merged` so project `.env` PORT applies before spawn.
|
|
*/
|
|
export function resolveRuntimePorts(fromEnv = process.env) {
|
|
const basePort = parsePort(fromEnv.PORT || "20128", 20128);
|
|
const apiPort = parsePort(fromEnv.API_PORT || String(basePort), basePort);
|
|
const dashboardPort = parsePort(fromEnv.DASHBOARD_PORT || String(basePort), basePort);
|
|
|
|
return { basePort, apiPort, dashboardPort };
|
|
}
|
|
|
|
export function withRuntimePortEnv(env, runtimePorts) {
|
|
const { basePort, apiPort, dashboardPort } = runtimePorts;
|
|
|
|
return {
|
|
...env,
|
|
OMNIROUTE_PORT: String(basePort),
|
|
PORT: String(dashboardPort),
|
|
DASHBOARD_PORT: String(dashboardPort),
|
|
API_PORT: String(apiPort),
|
|
};
|
|
}
|
|
|
|
export function sanitizeColorEnv(env = {}) {
|
|
const sanitized = { ...env };
|
|
|
|
// Node warns when both FORCE_COLOR and NO_COLOR are set.
|
|
// Prefer NO_COLOR in test tooling to avoid noisy process warnings.
|
|
if (typeof sanitized.FORCE_COLOR !== "undefined" && typeof sanitized.NO_COLOR !== "undefined") {
|
|
delete sanitized.FORCE_COLOR;
|
|
}
|
|
|
|
return sanitized;
|
|
}
|
|
|
|
export function spawnWithForwardedSignals(command, args, options = {}) {
|
|
const child = spawn(command, args, options);
|
|
|
|
child.on("exit", (code, signal) => {
|
|
if (signal) {
|
|
process.kill(process.pid, signal);
|
|
return;
|
|
}
|
|
process.exit(code ?? 0);
|
|
});
|
|
|
|
process.on("SIGINT", () => child.kill("SIGINT"));
|
|
process.on("SIGTERM", () => child.kill("SIGTERM"));
|
|
|
|
return child;
|
|
}
|