mqtt_logger: cached values carry no staleness information and connection gaps are invisible #3

Closed
opened 2026-09-09 01:33:04 +00:00 by agent-pi · 1 comment
Collaborator

Cached topics (forecasts, Zappi state, weather auxiliaries) persist their last received value indefinitely. If a publisher dies or stops sending, records keep being emitted that look complete but carry arbitrarily old values, and nothing in the stream reveals this.

Separately, nothing is recorded about connection lifecycle: the 2026-07-03 to 2026-07-13 hole in the stats file has no forensics trail - it is impossible to tell whether the logger died, the broker restarted, or the machine was off.

A related hazard: the client subscribes once at startup and uses a clean session, so after a broker restart it may reconnect successfully while subscribed to nothing - silently receiving no data until manually restarted.

Cached topics (forecasts, Zappi state, weather auxiliaries) persist their last received value indefinitely. If a publisher dies or stops sending, records keep being emitted that look complete but carry arbitrarily old values, and nothing in the stream reveals this. Separately, nothing is recorded about connection lifecycle: the 2026-07-03 to 2026-07-13 hole in the stats file has no forensics trail - it is impossible to tell whether the logger died, the broker restarted, or the machine was off. A related hazard: the client subscribes once at startup and uses a clean session, so after a broker restart it may reconnect successfully while subscribed to nothing - silently receiving no data until manually restarted.
Author
Collaborator

Findings

  • cached: True topic values persist in latest forever; there is no record of when each field was last published, so a dead publisher is indistinguishable from a fresh one.
  • Installed paho-mqtt source confirms: clean_session defaults to True (client.py) and there is no automatic resubscribe anywhere in client.py. Subscribing once in main() means a broker restart can leave the client connected but receiving nothing — a plausible cause of the silent multi-day gap in July.
  • Callback API VERSION2 signatures confirmed from the installed package: on_connect(client, userdata, connect_flags, reason_code, properties) / on_disconnect(client, userdata, disconnect_flags, reason_code, properties).

Plan of attack

  • Track published_at (monotonic) per field, updated atomically together with the value cache; each record gains an _age_s map covering exactly its payload fields, so analysis can reject records whose cached sources went quiet.
  • Add on_connect / on_disconnect handlers emitting JSON event lines ("event": "connect"/"disconnect", with reason_code) into the same stream; on_connect resubscribes to all topics (fixes the silent-reconnect hole). Move subscription from main() into on_connect as the single source of truth.
  • Verify end-to-end with a local mosquitto lifecycle: connect marker, record, broker kill, disconnect marker, broker restart, connect marker, records resume.
  • Commit: :sparkles: add per-field freshness ages and connect/disconnect markers on branch fix/issue-2-mqtt-logger-quality.
**Findings** - `cached: True` topic values persist in `latest` forever; there is no record of when each field was last published, so a dead publisher is indistinguishable from a fresh one. - Installed paho-mqtt source confirms: `clean_session` defaults to True (client.py) and there is no automatic resubscribe anywhere in `client.py`. Subscribing once in `main()` means a broker restart can leave the client connected but receiving nothing — a plausible cause of the silent multi-day gap in July. - Callback API VERSION2 signatures confirmed from the installed package: `on_connect(client, userdata, connect_flags, reason_code, properties)` / `on_disconnect(client, userdata, disconnect_flags, reason_code, properties)`. **Plan of attack** - Track `published_at` (monotonic) per field, updated atomically together with the value cache; each record gains an `_age_s` map covering exactly its payload fields, so analysis can reject records whose cached sources went quiet. - Add `on_connect` / `on_disconnect` handlers emitting JSON event lines (`"event": "connect"/"disconnect"`, with `reason_code`) into the same stream; `on_connect` resubscribes to all topics (fixes the silent-reconnect hole). Move subscription from `main()` into `on_connect` as the single source of truth. - Verify end-to-end with a local mosquitto lifecycle: connect marker, record, broker kill, disconnect marker, broker restart, connect marker, records resume. - Commit: `:sparkles: add per-field freshness ages and connect/disconnect markers` on branch `fix/issue-2-mqtt-logger-quality`.
Sign in to join this conversation.
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
marvin8/IrradiationToPowerProduction#3
No description provided.