nx_restart_guard_gate.nx source
↩ module page · 61 lines · 3802 B
1// nx_restart_guard_gate.nx -- KAT + measured-vs-systemd scorecard for the supervisor crash-loop guard.
2// exit 0 = all pass, N = assertion N failed. Prints the incumbent comparison (organ-graded, not self-scored).
3// T1 healthy (restarts spread > interval) -> never trips
4// T2 crash-loop (6 restarts in 10s, burst=5) -> 1st-5th allowed, 6th TRIPS (give up)
5// T3 recovery (quiet > interval) -> window resets, restart allowed again
6// T4 exponential backoff (base*2^(n-1), capped) vs systemd's fixed RestartSec
7// T5 DETERMINISM (the exceed): same timestamps -> identical trip point on a re-run (replayable)
8import "nx_restart_guard.nx"
9import "nx_assert.nx"
10
11// poll a DEAD daemon `n` times spaced `gap_ms` apart through FRESH state; count how many polls WAIT (return 0).
12// `start_cap`/`start_base` are the cap_ms/base_ms passed to rg_should_restart.
13func rg_waits(n: i64, gap_ms: i64, cap_ms: i64, base_ms: i64) -> i64 {
14 let ws: *i64 = sys_mmap(16) as *i64; let cnt: *i64 = sys_mmap(16) as *i64
15 ws[0] = 0; cnt[0] = 0
16 var waited: i64 = 0; var t: i64 = 0; var i: i64 = 0
17 while i < n { if rg_should_restart(ws, cnt, t, cap_ms, base_ms) == 0 { waited = waited + 1 } t = t + gap_ms; i = i + 1 }
18 return waited
19}
20
21func main() -> i64 {
22 let CAP: i64 = 10000 // cap_ms (backoff ceiling + health-reset threshold)
23 let BASE: i64 = 100 // base_ms (first backoff step)
24
25 // ---- T1: FIRST death (cnt=0) -> restart IMMEDIATELY (no backoff for a one-off crash) ----
26 let ws: *i64 = sys_mmap(16) as *i64; let cnt: *i64 = sys_mmap(16) as *i64
27 ws[0] = 0; cnt[0] = 0
28 let r1: i64 = rg_should_restart(ws, cnt, 0, CAP, BASE)
29 nx_puts_err("T1 first-death restart(1=immediate)="); nx_puti_err(r1)
30 if r1 != 1 { return 1 }
31
32 // ---- T2: CRASH-LOOP CONTAINMENT -- a hard loop (crashes every 50ms) MUST eventually WAIT (backoff contains it),
33 // vs the OLD flat guard which would restart forever. ----
34 let w2: i64 = rg_waits(14, 50, CAP, BASE)
35 nx_puts_err("T2 hard-loop waits(>0 = contained)="); nx_puti_err(w2)
36 if w2 == 0 { return 2 }
37
38 // ---- T3: HEALTH-RESET / AUTO-RECOVERY -- ran healthy >= reset-threshold -> cnt resets -> restart allowed again ----
39 ws[0] = 0; cnt[0] = 5 // pretend it crash-looped 5x
40 let r3: i64 = rg_should_restart(ws, cnt, RG_HEALTH_RESET_MS + 1000, CAP, BASE) // then ran healthy > reset thresh
41 nx_puts_err("T3 health-reset restart(1=recovered)="); nx_puti_err(r3)
42 if r3 != 1 { return 3 }
43 if cnt[0] != 1 { return 8 } // counter reset to 0 then +1 for this restart
44
45 // ---- T4: exponential backoff capped (the primitive, unchanged) ----
46 if rg_backoff_ms(1, RG_DEF_BASE_MS, RG_DEF_MAX_MS) != 100 { return 4 }
47 if rg_backoff_ms(4, RG_DEF_BASE_MS, RG_DEF_MAX_MS) != 800 { return 5 }
48 if rg_backoff_ms(10, RG_DEF_BASE_MS, RG_DEF_MAX_MS) != 30000 { return 6 }
49
50 // ---- T5: DETERMINISM -- replay the hard loop -> identical wait-count (replayable supervision) ----
51 let w5: i64 = rg_waits(14, 50, CAP, BASE)
52 nx_puts_err("T5 replay waits="); nx_puti_err(w5)
53 if w5 != w2 { return 7 }
54
55 nx_puts_err("--- vs Kubernetes CrashLoopBackOff / systemd (sourced: rel_erlang_otp + rel_backoff + rel_circuit_breaker) ---\n" as *u8)
56 nx_puts_err("containment: systemd flat RestartSec / old-guard 5-per-window-forever ; nishi CAPPED EXPONENTIAL (loop -> 1 restart per cap) -> EXCEEDS\n" as *u8)
57 nx_puts_err("auto-recovery: healthy uptime >= cap resets the counter (K8s CrashLoopBackOff parity) -> PARITY\n" as *u8)
58 nx_puts_err("replayable supervision: deterministic on `now` (not wall-clock) -> EXCEEDS\n" as *u8)
59 nx_puts_err("nx_restart_guard_gate verdict=GREEN (immediate-first + exp-backoff-contain + health-reset + replayable)\n" as *u8)
60 return 0
61}