From b3358f77a3fb9062ae831a9a3a9da8f6647ae4ba Mon Sep 17 00:00:00 2001 From: Dushnilin Date: Thu, 3 Sep 2026 06:13:30 +0300 Subject: [PATCH] fix(stability): optimize Go memory tiers, prevent nftables degradation deadlock, harden NTP & process supervision - singbox/runtime.uc: add dynamic 4-tier GOMEMLIMIT and GOGC limits based on RAM, enforce /etc/tachyon/mem_scale, and install managed init script across all binary variants - service/event_controller.uc: guard probe_nftables() with recovery_bypass and native_internet_restored checks to prevent 5-minute network drop deadlock - service/watchdog.uc: reduce Telegram worker heartbeat timeout from 900s to 300s and add nslookup fallback to Zero-RTT prefetcher - diagnostics/runtime.uc & service/lifecycle.uc: use direct-IP NTP pool to eliminate circular DNS/TLS deadlocks, and step clock forward on cold boot if RTC desynced - service/failover.uc & diagnostics/runtime.uc: flush conntrack states on proxy group switch so client connections immediately migrate --- tachyon/files/usr/lib/diagnostics/runtime.uc | 4 +- .../files/usr/lib/service/event_controller.uc | 3 ++ tachyon/files/usr/lib/service/failover.uc | 1 + tachyon/files/usr/lib/service/lifecycle.uc | 5 +++ tachyon/files/usr/lib/service/watchdog.uc | 4 +- tachyon/files/usr/lib/singbox/runtime.uc | 38 +++++++++++++++---- 6 files changed, 44 insertions(+), 11 deletions(-) diff --git a/tachyon/files/usr/lib/diagnostics/runtime.uc b/tachyon/files/usr/lib/diagnostics/runtime.uc index 631bae17..25a5397b 100644 --- a/tachyon/files/usr/lib/diagnostics/runtime.uc +++ b/tachyon/files/usr/lib/diagnostics/runtime.uc @@ -1864,6 +1864,8 @@ function clash_api(action, arg1, arg2, arg3) { push(args, "--data-raw"); push(args, payload); let result = status_capture([ "clash-set-group-proxy-result", arg1, arg2 ], command_output(command_from_args(args))); + if (result.status == 0) + command_status("conntrack -F >/dev/null 2>&1 || true"); if (result.output != "") print(result.output); return result.status; @@ -3930,7 +3932,7 @@ function apply_quick_fix(codes_str) { status = (rc == 0); msg = status ? "Tachyon stopped, stock dnsmasq and native direct internet routing restored" : "Native internet restore failed (exit " + rc + ")"; } else if (c == "fix_system_time") { - let rc = command_status("ntpd -q -p pool.ntp.org 2>/dev/null || rdate -s time.cloudflare.com 2>/dev/null; /etc/init.d/sysntpd restart 2>/dev/null"); + let rc = command_status("ntpd -q -p 194.190.168.1 -p 216.239.35.0 -p 162.159.200.1 2>/dev/null || ntpd -q -p pool.ntp.org 2>/dev/null || rdate -s time.cloudflare.com 2>/dev/null; /etc/init.d/sysntpd restart 2>/dev/null"); status = (rc == 0); msg = status ? "System time synchronized with NTP" : "NTP sync failed (exit " + rc + ")"; } else if (c == "flush_conntrack") { diff --git a/tachyon/files/usr/lib/service/event_controller.uc b/tachyon/files/usr/lib/service/event_controller.uc index 84bf5751..5c03c919 100644 --- a/tachyon/files/usr/lib/service/event_controller.uc +++ b/tachyon/files/usr/lib/service/event_controller.uc @@ -642,6 +642,8 @@ function controller(bus, opts) { // ── Probe: nftables table and QoS marks ─────────────────────────────────── function probe_nftables() { + if (setting("recovery_bypass", "0") == "1") return; + if (fs.stat("/var/run/tachyon/native_internet_restored") != null) return; if (is_list_update_running()) return; if (is_reload_in_progress()) return; @@ -666,6 +668,7 @@ function controller(bus, opts) { // ── Probe: TPROXY port liveness ─────────────────────────────────────────── function probe_tproxy() { if (setting("recovery_bypass", "0") == "1") return; + if (fs.stat("/var/run/tachyon/native_internet_restored") != null) return; if (is_reload_in_progress()) return; let pid = get_sing_box_pid(); diff --git a/tachyon/files/usr/lib/service/failover.uc b/tachyon/files/usr/lib/service/failover.uc index 965cb3c4..a91c9830 100644 --- a/tachyon/files/usr/lib/service/failover.uc +++ b/tachyon/files/usr/lib/service/failover.uc @@ -121,6 +121,7 @@ function switch_group(section_name, outbound_name) { log_message("runtime switch failed: " + out, "warn"); return false; } + command_status("conntrack -F >/dev/null 2>&1 || true"); return true; } diff --git a/tachyon/files/usr/lib/service/lifecycle.uc b/tachyon/files/usr/lib/service/lifecycle.uc index 1fe5190c..476800c6 100644 --- a/tachyon/files/usr/lib/service/lifecycle.uc +++ b/tachyon/files/usr/lib/service/lifecycle.uc @@ -835,6 +835,11 @@ function start_impl() { if (wd_status != 0) log_message("Watchdog start-runtime failed (status " + as_string(wd_status) + ")", "warn"); + if (time() < 1704067200) { + log_message("System clock is in the past (RTC desync); performing quick NTP synchronization...", "warn"); + command_status("ntpd -q -p 194.190.168.1 -p 216.239.35.0 -p 162.159.200.1 >/dev/null 2>&1 || true"); + } + let status = start_main(); if (status != 0) return status; diff --git a/tachyon/files/usr/lib/service/watchdog.uc b/tachyon/files/usr/lib/service/watchdog.uc index e3b9b674..c4d43839 100644 --- a/tachyon/files/usr/lib/service/watchdog.uc +++ b/tachyon/files/usr/lib/service/watchdog.uc @@ -349,7 +349,7 @@ function run_zero_rtt_prefetching() { // that followed it attached to a null command in this shell instead // of to the backgrounded loop. Backgrounding is now the wrapper's // job, so the loop gets the redirections it was always meant to have. - let batch_cmd = "for d in " + join(" ", batch) + "; do dig @127.0.0.1 \"$d\" A >/dev/null 2>&1; done"; + let batch_cmd = "for d in " + join(" ", batch) + "; do dig @127.0.0.1 \"$d\" A >/dev/null 2>&1 || nslookup \"$d\" 127.0.0.1 >/dev/null 2>&1; done"; system(common.background_command(batch_cmd)); batch = []; } @@ -1976,7 +1976,7 @@ function check_telegram_worker() { } let age = time() - int(heartbeat); - if (age <= 900) + if (age <= 300) return; let pid = trim(fs.readfile(TELEGRAM_PID_FILE) || ""); diff --git a/tachyon/files/usr/lib/singbox/runtime.uc b/tachyon/files/usr/lib/singbox/runtime.uc index cc5f2225..0f606af3 100644 --- a/tachyon/files/usr/lib/singbox/runtime.uc +++ b/tachyon/files/usr/lib/singbox/runtime.uc @@ -369,7 +369,7 @@ function owner_pid() { function managed_service_installed() { let data = fs.readfile("/etc/init.d/sing-box"); - return data != null && index(as_string(data), SB_MANAGED_SERVICE_MARKER) >= 0; + return data != null && index(as_string(data), SB_MANAGED_SERVICE_MARKER) >= 0 && index(as_string(data), "GOGC") >= 0; } function managed_service_text() { @@ -381,7 +381,7 @@ function managed_service_text() { "start_service() {\n" + " config_load \"sing-box\"\n" + " local enabled config_file working_directory\n" + - " local log_stderr mem_total_kb mem_limit_mb\n\n" + + " local log_stderr mem_total_kb mem_limit_mb gogc scale scale_pct\n\n" + " config_get_bool enabled \"main\" \"enabled\" \"0\"\n" + " [ \"$enabled\" -eq \"1\" ] || return 0\n\n" + " config_get config_file \"main\" \"conffile\" \"/etc/sing-box/config.json\"\n" + @@ -394,10 +394,32 @@ function managed_service_text() { " procd_set_param limits core=\"unlimited\"\n" + " procd_set_param limits nofile=\"1000000 1000000\"\n" + " mem_total_kb=\"$(awk '/MemTotal/ {print $2}' /proc/meminfo 2>/dev/null || echo 0)\"\n" + - " if [ \"$mem_total_kb\" -gt 0 ] && [ \"$mem_total_kb\" -lt 262144 ]; then\n" + - " mem_limit_mb=$(( mem_total_kb / 1024 * 35 / 100 ))\n" + - " [ \"$mem_limit_mb\" -lt 24 ] && mem_limit_mb=24\n" + - " procd_set_param env GOMEMLIMIT=\"${mem_limit_mb}MiB\"\n" + + " if [ \"$mem_total_kb\" -gt 0 ]; then\n" + + " if [ \"$mem_total_kb\" -lt 131072 ]; then\n" + + " mem_limit_mb=$(( mem_total_kb / 1024 * 30 / 100 ))\n" + + " [ \"$mem_limit_mb\" -lt 16 ] && mem_limit_mb=16\n" + + " gogc=20\n" + + " elif [ \"$mem_total_kb\" -lt 262144 ]; then\n" + + " mem_limit_mb=$(( mem_total_kb / 1024 * 35 / 100 ))\n" + + " [ \"$mem_limit_mb\" -lt 24 ] && mem_limit_mb=24\n" + + " gogc=25\n" + + " elif [ \"$mem_total_kb\" -lt 524288 ]; then\n" + + " mem_limit_mb=$(( mem_total_kb / 1024 * 40 / 100 ))\n" + + " gogc=30\n" + + " else\n" + + " mem_limit_mb=$(( mem_total_kb / 1024 * 30 / 100 ))\n" + + " [ \"$mem_limit_mb\" -gt 256 ] && mem_limit_mb=256\n" + + " gogc=40\n" + + " fi\n" + + " if [ -r \"/etc/tachyon/mem_scale\" ]; then\n" + + " scale=\"$(cat /etc/tachyon/mem_scale 2>/dev/null)\"\n" + + " scale_pct=\"$(awk -v s=\"$scale\" 'BEGIN { pct=int(s*100); if (pct < 20) pct=20; if (pct > 100) pct=100; print pct }')\"\n" + + " if [ -n \"$scale_pct\" ] && [ \"$scale_pct\" -lt 100 ]; then\n" + + " mem_limit_mb=$(( mem_limit_mb * scale_pct / 100 ))\n" + + " [ \"$mem_limit_mb\" -lt 12 ] && mem_limit_mb=12\n" + + " fi\n" + + " fi\n" + + " procd_set_param env GOMEMLIMIT=\"${mem_limit_mb}MiB\" GOGC=\"$gogc\"\n" + " fi\n" + " procd_set_param term_timeout 15\n" + " procd_set_param respawn\n" + @@ -450,8 +472,8 @@ function prepare_service_disabled() { function configure_service() { let settings = uci_settings(); - if (sing_box_compressed_marker_set() && !install_managed_service_script()) { - log_message("Failed to install managed sing-box service for compressed binary. Aborted.", "fatal"); + if (!managed_service_installed() && !install_managed_service_script()) { + log_message("Failed to install managed sing-box service. Aborted.", "fatal"); exit(1); }