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:
@@ -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) ]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) ]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user