Harden mqtt_logger against partial payloads, stale cache values, and silent reconnects #4
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/issue-2-mqtt-logger-quality"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Three related fixes to the MQTT stats logger, developed TDD-style with a new standalone unittest suite (
test_mqtt_logger.py, matching thetest_analyze.pyconventions).Atomic payload extraction — a JSON topic payload missing one of its expected fields used to leave the fields before it already merged into the cache, producing records that mixed half-delivered values with stale cache. Extraction now happens into a temporary dict merged only when the payload is complete. Closes #2.
Per-field freshness ages — every record now carries an
_age_smap (seconds since each field was last published), so analysis can reject records whose cached sources (forecasts, Zappi state, weather) went quiet instead of mistaking stale values for fresh ones. Closes #3.Connection markers + resubscribe —
on_connect/on_disconnectemit JSON event lines into the same stream, making broker restarts and network gaps attributable in the stats file (the 2026-07-03..13 gap had no forensics trail).on_connectalso resubscribes to every topic: paho uses a clean session and does not restore subscriptions, so a broker restart previously risked a connected-but-deaf logger.Verified against a local mosquitto lifecycle: connect marker, record, broker kill, disconnect marker, broker restart, connect marker, records resume; 11 logger tests + 6 analyze tests green.
Also documents the new metadata in
mqtt-topic-logger.md/AGENTS.md, and lands the Working Conventions change adopting the standard forge workflow.Closes #2
Closes #3
@ -112,1 +113,4 @@fresh: set = set()# field -> monotonic() reading of its last successful publish; drives _age_s# so downstream analysis can reject records carrying stale cached values.published_at: dict = {}Do we at this point already know what types store in this dict? If so we should be more specific with our typing!
mqtt_logger.pyline 116✅ Yes — every value written is a
time.monotonic()reading, so the keys are field names and the values are floats. Typed asdict[str, float]in commit169eecf.The two sibling declarations are vaguer than they could be — want me to tighten those too?
latest: dict[str, str | int | float | bool](raw topics store decoded strings; JSON topics yield scalars) andfresh: set[str].Following up on the
published_attyping thread — both sibling declarations tightened in commit25ddb19:latest: dict[str, str | int | float | bool]— raw-key topics store decoded strings, JSON-extracted fields are scalarsfresh: set[str]— topic namesAll 11 logger tests green.
25ddb19d8eto78ebbb453bNew commits pushed, approval review dismissed automatically according to repository settings