From fdab25b09883b982157950ea50ed131d5cc19b40 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Thu, 23 Apr 2026 22:17:25 +0200 Subject: [PATCH] core: auto-size NODE_OPTIONS heap (#13960) * feat(nodejs): auto-size NODE_OPTIONS heap and apply in Termix updates - setup_nodejs now sets NODE_OPTIONS only when not already set - Heap size is auto-derived from NODE_MAX_OLD_SPACE_SIZE, var_ram, or MemTotal - Auto heap is clamped to 1024..4096 MB to avoid too-small or too-large defaults - Termix update path now calls setup_nodejs before frontend/backend builds so Node heap defaults are applied consistently during updates * feat(error-handler): add actionable Node.js heap OOM guidance Detect probable Node.js heap out-of-memory failures from log patterns and common build exit codes, then print targeted remediation hints instead of only a generic SIGABRT/SIGKILL message. - Detect OOM patterns in last log lines (Reached heap limit, JS heap OOM) - Treat node build contexts with exit 134/137/243 as likely heap issues - Suggest computed --max-old-space-size based on NODE_OPTIONS, var_ram, or MemTotal (clamped to 1024..4096 MB) - Recommend calling setup_nodejs before build steps so defaults apply * refactor(node-heap): raise auto cap to 12GB and simplify OOM hint - Increase setup_nodejs auto heap clamp from 4GB to 12GB for heavy frontend builds - Keep lower bound at 1GB and preserve user override precedence - Simplify error_handler Node OOM output to a single concise hint - Align error_handler heap suggestion clamp to 12GB --- ct/termix.sh | 2 ++ misc/error_handler.func | 45 +++++++++++++++++++++++++++++++++++++++++ misc/tools.func | 32 ++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/ct/termix.sh b/ct/termix.sh index cac5acfa1..fac375992 100644 --- a/ct/termix.sh +++ b/ct/termix.sh @@ -155,6 +155,8 @@ EOF /opt/termix/nginx/client_body msg_ok "Recreated Directories" + NODE_VERSION="24" setup_nodejs + msg_info "Building Frontend" cd /opt/termix export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 diff --git a/misc/error_handler.func b/misc/error_handler.func index dd816dc22..50e8dac42 100644 --- a/misc/error_handler.func +++ b/misc/error_handler.func @@ -313,6 +313,51 @@ error_handler() { echo -e "${TAB}-----------------------------------\n" fi + # Detect probable Node.js heap OOM and print actionable guidance. + # This avoids generic SIGABRT/SIGKILL confusion for frontend build failures. + local node_oom_detected="false" + local node_build_context="false" + if [[ "$command" =~ (npm|pnpm|yarn|node|vite|turbo) ]]; then + node_build_context="true" + fi + if [[ "$exit_code" == "243" ]]; then + node_oom_detected="true" + elif [[ -n "$active_log" && -s "$active_log" ]]; then + if tail -n 200 "$active_log" 2>/dev/null | grep -Eqi 'Reached heap limit|JavaScript heap out of memory|Allocation failed - JavaScript heap out of memory|FATAL ERROR: Reached heap limit'; then + node_oom_detected="true" + fi + fi + + if [[ "$node_oom_detected" == "true" ]] || { [[ "$node_build_context" == "true" ]] && [[ "$exit_code" =~ ^(134|137)$ ]]; }; then + local heap_hint_mb="" + + # If explicitly configured, prefer the current value for troubleshooting output. + if [[ -n "${NODE_OPTIONS:-}" ]] && [[ "${NODE_OPTIONS}" =~ max-old-space-size=([0-9]+) ]]; then + heap_hint_mb="${BASH_REMATCH[1]}" + elif [[ -n "${var_ram:-}" ]] && [[ "${var_ram}" =~ ^[0-9]+$ ]]; then + heap_hint_mb=$((var_ram * 75 / 100)) + else + local mem_kb="" + mem_kb=$(awk '/^MemTotal:/ {print $2; exit}' /proc/meminfo 2>/dev/null || echo "") + if [[ "$mem_kb" =~ ^[0-9]+$ ]]; then + local mem_mb=$((mem_kb / 1024)) + heap_hint_mb=$((mem_mb * 75 / 100)) + fi + fi + + if [[ -z "$heap_hint_mb" ]] || ((heap_hint_mb < 1024)); then + heap_hint_mb=1024 + elif ((heap_hint_mb > 12288)); then + heap_hint_mb=12288 + fi + + if declare -f msg_warn >/dev/null 2>&1; then + msg_warn "Possible Node.js heap OOM. Try: export NODE_OPTIONS=\"--max-old-space-size=${heap_hint_mb}\" and rerun the build." + else + echo -e "${YW}Possible Node.js heap OOM. Try: export NODE_OPTIONS=\"--max-old-space-size=${heap_hint_mb}\" and rerun the build.${CL}" + fi + fi + # Detect context: Container (INSTALL_LOG set + inside container /root) vs Host if [[ -n "${INSTALL_LOG:-}" && -f "${INSTALL_LOG:-}" && -d /root ]]; then # CONTAINER CONTEXT: Copy log and create flag file for host diff --git a/misc/tools.func b/misc/tools.func index 751210ed9..81621a8f3 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -6423,7 +6423,37 @@ function setup_nodejs() { msg_ok "Setup Node.js $NODE_VERSION" fi - export NODE_OPTIONS="--max-old-space-size=4096" + # Set a safe default heap limit for Node.js builds if not explicitly provided. + # Priority: + # 1) NODE_OPTIONS (caller/user override) + # 2) NODE_MAX_OLD_SPACE_SIZE (explicit MB override) + # 3) var_ram (LXC memory setting, MB) + # 4) /proc/meminfo (runtime memory detection) + # Auto value is clamped to 1024..12288 MB. + if [[ -z "${NODE_OPTIONS:-}" ]]; then + local node_heap_mb="" + + if [[ -n "${NODE_MAX_OLD_SPACE_SIZE:-}" ]] && [[ "${NODE_MAX_OLD_SPACE_SIZE}" =~ ^[0-9]+$ ]]; then + node_heap_mb="${NODE_MAX_OLD_SPACE_SIZE}" + elif [[ -n "${var_ram:-}" ]] && [[ "${var_ram}" =~ ^[0-9]+$ ]]; then + node_heap_mb=$((var_ram * 75 / 100)) + else + local total_mem_kb="" + total_mem_kb=$(awk '/^MemTotal:/ {print $2; exit}' /proc/meminfo 2>/dev/null || echo "") + if [[ "$total_mem_kb" =~ ^[0-9]+$ ]]; then + local total_mem_mb=$((total_mem_kb / 1024)) + node_heap_mb=$((total_mem_mb * 75 / 100)) + fi + fi + + if [[ -z "$node_heap_mb" ]] || ((node_heap_mb < 1024)); then + node_heap_mb=1024 + elif ((node_heap_mb > 12288)); then + node_heap_mb=12288 + fi + + export NODE_OPTIONS="--max-old-space-size=${node_heap_mb}" + fi # Ensure valid working directory for npm (avoids uv_cwd error) if [[ ! -d /opt ]]; then