fix(reliability): converge runtime on uplink revert; bound health endpoint cost (I3,I4)
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user