feat(import): v0.16.0 - Fully implemented series 3 BW-ACH pipeline stablized. #19

Merged
serversdown merged 9 commits from ach-report-ingestion into main 2026-05-11 15:55:24 -04:00
Showing only changes of commit cc57a8e618 - Show all commits
+74 -16
View File
@@ -564,21 +564,79 @@ class SeismoDb:
def query_units(self) -> list[dict]: def query_units(self) -> list[dict]:
""" """
Return one row per known serial with summary stats: Return one row per known serial with summary stats.
last_seen, total_events, total_monitor_entries.
Aggregates from BOTH source tables:
- `events` — populated by every ingest path
(live ACH, /db/import/blastware_file
from the series3-watcher forwarder, etc.)
- `ach_sessions` — only populated by the live ACH server;
empty for events that came in via the
BW-importer route.
Earlier this method only joined on `ach_sessions`, which made
watcher-forwarded units invisible to the SFM webapp's fleet
overview even though their events were correctly populated in
`events`. Now we union the two and surface every serial that
has activity in either table.
Fields:
serial — unit serial number (e.g. "BE11529")
last_seen — most recent of MAX(events.timestamp)
and MAX(ach_sessions.session_time)
total_events — COUNT(*) from `events` (the
authoritative count regardless of
ingest path)
total_monitor_entries — from `ach_sessions`, 0 when absent
total_sessions — COUNT(*) from `ach_sessions`, 0 when absent
""" """
with self._connect() as conn: with self._connect() as conn:
rows = conn.execute( event_stats = {
""" row["serial"]: row
SELECT for row in conn.execute(
s.serial, """
MAX(s.session_time) AS last_seen, SELECT serial,
SUM(s.events_downloaded) AS total_events, MAX(timestamp) AS last_event_at,
SUM(s.monitor_entries) AS total_monitor_entries, COUNT(*) AS total_events
COUNT(*) AS total_sessions FROM events
FROM ach_sessions s GROUP BY serial
GROUP BY s.serial """,
ORDER BY last_seen DESC ).fetchall()
""" }
).fetchall() session_stats = {
return [dict(r) for r in rows] row["serial"]: row
for row in conn.execute(
"""
SELECT serial,
MAX(session_time) AS last_session_at,
SUM(monitor_entries) AS total_monitor_entries,
COUNT(*) AS total_sessions
FROM ach_sessions
GROUP BY serial
""",
).fetchall()
}
all_serials = set(event_stats) | set(session_stats)
units = []
for serial in all_serials:
e = event_stats.get(serial)
s = session_stats.get(serial)
last_event_at = e["last_event_at"] if e else None
last_session_at = s["last_session_at"] if s else None
# Prefer whichever timestamp is more recent
last_seen = max(
(t for t in (last_event_at, last_session_at) if t),
default=None,
)
units.append({
"serial": serial,
"last_seen": last_seen,
"total_events": e["total_events"] if e else 0,
"total_monitor_entries": s["total_monitor_entries"] if s else 0,
"total_sessions": s["total_sessions"] if s else 0,
})
# Sort by last_seen desc; serials with no timestamp at all sink to the bottom.
units.sort(key=lambda u: u.get("last_seen") or "", reverse=True)
return units