fix(reliability): converge runtime on uplink revert; bound health endpoint cost (I3,I4)

This commit is contained in:
2026-08-22 16:52:29 -06:00
parent b25c98b7c7
commit 60db235f0b
5 changed files with 104 additions and 2 deletions
@@ -1,5 +1,6 @@
"""Mark VIII reliability event journal. JSONL on /mmc, rotated."""
import json, os, threading, time
from collections import deque
MK8_DIR = '/mmc/mk8'
EVENTS_PATH = os.path.join(MK8_DIR, 'events.log')
@@ -87,6 +88,43 @@ def counters():
return counts
def snapshot(event_limit=20, scan=2000):
"""Newest-first events (up to event_limit) plus kind counters computed
over at most `scan` most-recent entries, in ONE parse pass. Bounded so a
large rotated journal cannot spike memory/CPU on every health poll."""
events = []
counts = {v: 0 for v in _COUNTER_KEYS.values()}
scanned = 0
paths = [EVENTS_PATH]
paths.extend(EVENTS_PATH + '.%d' % i for i in range(KEEP, 0, -1))
tail_len = max(scan, event_limit)
for path in paths:
if len(events) >= event_limit and scanned >= scan:
break
try:
with open(path) as f:
tail = deque((l for l in f if l.strip()), maxlen=tail_len)
except OSError:
continue
for line in reversed(tail):
try:
row = json.loads(line)
except ValueError:
continue
if not isinstance(row, dict):
continue
scanned += 1
kind = row.get('kind')
if kind in _COUNTER_KEYS:
counts[_COUNTER_KEYS[kind]] += 1
if len(events) < event_limit:
events.append(row)
if len(events) >= event_limit and scanned >= scan:
break
events.sort(key=lambda r: r.get('ts', 0), reverse=True)
return {'events': events[:event_limit], 'reliability': counts}
def mark_boot(unexpected=False):
log_event('unexpected_boot' if unexpected else 'boot', sev='warn'
if unexpected else 'info',
@@ -94,6 +94,11 @@ def set_role(role, ssid=None, psk=None):
break
if not assoc:
disable_uplink()
# UCI alone does not converge runtime: without a reload wlan1up
# keeps scanning/authenticating and pins phy1 until some unrelated
# future reload, while current_role() already reports idle.
# Converge now like the idle branch, then reapply the hop policy.
device_run(['wifi', 'reload'], timeout=60)
_resume_hop()
return {'ok': False, 'error': 'association failed; reverted'}
return {'ok': True, 'role': 'uplink', 'assoc': assoc}
@@ -4808,8 +4808,9 @@ def h_health(ctx):
for k in ('pass', 'fixed', 'warn', 'fail')},
'steps': ENV_CHECK_STATE['report'],
}
h['reliability'] = mk8_events.counters()
h['events'] = mk8_events.read_events(limit=20)
snap = mk8_events.snapshot()
h['reliability'] = snap['reliability']
h['events'] = snap['events']
h['guard'] = mk8_guard.guard_report()
return 200, h