fix(watchdog,priority,dns_failover,providers): reduce CPU/memory footprint on low-end routers (1.3.20)

- priority.uc: replace 1s tight sleep loop with dynamic interval based on group config (5s default)
- dns_failover.uc: replace 1s sleep with min(active_interval, recovery_interval)
- watchdog.uc: cap pending_smart_domains at 500 entries, add 300s TTL expiry
- event_controller.uc: batch is_dns_working nslookup calls into single shell process
- byedpi/runtime.uc: add crash-loop backoff (up to 6x base delay after 5 rapid crashes)
- nfqueue/runtime.uc: same crash-loop backoff for nfqws supervisors
This commit is contained in:
Dushnilin
2026-09-04 19:44:20 +03:00
parent 69b6cf18ec
commit 529db5fc6c
6 changed files with 63 additions and 14 deletions
@@ -241,16 +241,31 @@ function supervisor_command(port, raw_opt, child_pidfile) {
}
function supervisor(section, port, raw_opt, child_pidfile) {
let crash_count = 0;
let base_delay = int(BYEDPI_RESPAWN_DELAY);
if (base_delay < 1) base_delay = 5;
while (true) {
if (!provider_available()) {
print(command_output_from_args([ "date", "+%Y-%m-%d %H:%M:%S" ]), " Provider ", BYEDPI_BIN, " is not executable; retrying in ", BYEDPI_RESPAWN_DELAY, " seconds\n");
command_success_from_args([ "sleep", BYEDPI_RESPAWN_DELAY ]);
print(command_output_from_args([ "date", "+%Y-%m-%d %H:%M:%S" ]), " Provider ", BYEDPI_BIN, " is not executable; retrying in ", base_delay, " seconds\n");
command_success_from_args([ "sleep", as_string(base_delay) ]);
continue;
}
let start_time = clock()[0];
let rc = command_status("sh -c " + shell_quote(supervisor_command(port, raw_opt, child_pidfile)));
print(command_output_from_args([ "date", "+%Y-%m-%d %H:%M:%S" ]), " ciadpi for rule ", as_string(section), " exited with code ", rc, "; respawning in ", BYEDPI_RESPAWN_DELAY, " seconds\n");
command_success_from_args([ "sleep", BYEDPI_RESPAWN_DELAY ]);
let elapsed = clock()[0] - start_time;
if (elapsed < 10) {
crash_count++;
if (crash_count > 5) crash_count = 5;
} else {
crash_count = 0;
}
let delay = base_delay * (1 + crash_count);
print(command_output_from_args([ "date", "+%Y-%m-%d %H:%M:%S" ]), " ciadpi for rule ", as_string(section), " exited with code ", rc, "; respawning in ", delay, " seconds\n");
command_success_from_args([ "sleep", as_string(delay) ]);
}
}
@@ -336,16 +336,31 @@ function supervisor_command(cfg, queue, raw_opt, child_pidfile) {
}
function supervisor(cfg, section, queue, raw_opt, child_pidfile) {
let crash_count = 0;
let base_delay = int(cfg.respawn_delay);
if (base_delay < 1) base_delay = 5;
while (true) {
if (!provider_available(cfg)) {
print(command_output_from_args([ "date", "+%Y-%m-%d %H:%M:%S" ]), " Provider ", cfg.binary, " is not executable; retrying in ", cfg.respawn_delay, " seconds\n");
command_success_from_args([ "sleep", cfg.respawn_delay ]);
print(command_output_from_args([ "date", "+%Y-%m-%d %H:%M:%S" ]), " Provider ", cfg.binary, " is not executable; retrying in ", base_delay, " seconds\n");
command_success_from_args([ "sleep", as_string(base_delay) ]);
continue;
}
let start_time = clock()[0];
let rc = command_status("sh -c " + shell_quote(supervisor_command(cfg, queue, raw_opt, child_pidfile)));
print(command_output_from_args([ "date", "+%Y-%m-%d %H:%M:%S" ]), " ", cfg.binary_name, " for rule ", as_string(section), " exited with code ", rc, "; respawning in ", cfg.respawn_delay, " seconds\n");
command_success_from_args([ "sleep", cfg.respawn_delay ]);
let elapsed = clock()[0] - start_time;
if (elapsed < 10) {
crash_count++;
if (crash_count > 5) crash_count = 5;
} else {
crash_count = 0;
}
let delay = base_delay * (1 + crash_count);
print(command_output_from_args([ "date", "+%Y-%m-%d %H:%M:%S" ]), " ", cfg.binary_name, " for rule ", as_string(section), " exited with code ", rc, "; respawning in ", delay, " seconds\n");
command_success_from_args([ "sleep", as_string(delay) ]);
}
}
@@ -167,9 +167,10 @@ function sing_box_in_proc() {
}
function is_dns_working() {
return command_success_from_args([ "nslookup", "-timeout=2", "yandex.ru", "127.0.0.1" ]) ||
command_success_from_args([ "nslookup", "-timeout=2", "connectivitycheck.gstatic.com", "127.0.0.1" ]) ||
command_success_from_args([ "nslookup", "-timeout=2", "google.com", "127.0.0.1" ]);
return command_success_from_args([ "sh", "-c",
"nslookup -timeout=2 yandex.ru 127.0.0.1 >/dev/null 2>&1 || " +
"nslookup -timeout=2 connectivitycheck.gstatic.com 127.0.0.1 >/dev/null 2>&1 || " +
"nslookup -timeout=2 google.com 127.0.0.1 >/dev/null 2>&1" ]);
}
function check_tachyon_cli_running() {
@@ -388,6 +388,8 @@ let last_restart_time = 0;
let last_reload_time = 0;
let pending_smart_domains = {};
let smart_detect_last_run = 0;
const PENDING_SMART_DOMAINS_MAX = 500;
const PENDING_SMART_DOMAINS_TTL = 300;
let last_fast_check = 0;
let last_normal_check = 0;
let last_slow_check = 0;
@@ -1417,6 +1419,12 @@ function smart_detect_process_pending() {
let now = time();
if (now - smart_detect_last_run < 30) return;
let stale_cutoff = now - PENDING_SMART_DOMAINS_TTL;
for (let dom in keys(pending_smart_domains)) {
if (pending_smart_domains[dom] < stale_cutoff)
delete pending_smart_domains[dom];
}
let domain_list = keys(pending_smart_domains);
if (length(domain_list) == 0) return;
smart_detect_last_run = now;
@@ -1546,6 +1554,7 @@ function heal_oom(ev) {
// smart_detect_process_pending(): probing inside the log handler would block
// the event loop on curl for every failing connection.
function collect_smart_detect_candidate(ev) {
if (length(pending_smart_domains) >= PENDING_SMART_DOMAINS_MAX) return;
pending_smart_domains[ev.payload.domain] = time();
}
@@ -283,6 +283,9 @@ function worker() {
let all_down = { main: false, bootstrap: false };
let strikes = { main: {}, bootstrap: {}, recovery_successes: { main: {}, bootstrap: {} } };
let sleep_interval = active_interval < recovery_interval ? active_interval : recovery_interval;
if (sleep_interval < 2) sleep_interval = 2;
while (true) {
let now = now_seconds();
let current_cfg = settings();
@@ -331,7 +334,7 @@ function worker() {
next_recovery = completed + recovery_interval;
}
command_success_from_args([ "sleep", "1" ]);
command_success_from_args([ "sleep", as_string(sleep_interval) ]);
}
}
+8 -2
View File
@@ -382,13 +382,19 @@ function worker() {
return 0;
let states = {};
for (let group in groups)
let min_interval = 5;
for (let group in groups) {
states[group.tag] = init_group_state(group);
let interval = duration_to_seconds(group.active_check_interval, 5);
if (interval < min_interval)
min_interval = interval;
}
if (min_interval < 1) min_interval = 1;
while (true) {
for (let group in groups)
tick_group(states[group.tag], group);
system("sleep 1");
command_success_from_args([ "sleep", as_string(min_interval) ]);
}
}