metrics: count LIST membership status, not the subscriber's own status

The first live run recorded newsletter_subs = 0 — a wrong zero, the exact
fail-open this module documents against. Cause: Listmonk's subscriber record
carries status enabled/blocked, while the LIST membership carries
subscription_status confirmed/unconfirmed. Filtering on the subscriber's own
status matched nothing and returned a silent 0.

Now counts memberships whose subscription_status is confirmed (verified: 71,
matching the list), and returns NULL when the endpoint yields no rows at all —
"not measured" rather than "nobody is subscribed". The daily job is the
regression test: it must record 71, not 0.
This commit is contained in:
inference-bot committed 2026-10-28 03:54:42 +00:00
1 parent 80de75672c
commit 27c32fc75f
1 file changed
+17 -2
+17 -2
View File
@@ -99,7 +99,7 @@ def from_listmonk() -> int | None:
print("metrics: LISTMONK_API_TOKEN not set — newsletter_subs left NULL") print("metrics: LISTMONK_API_TOKEN not set — newsletter_subs left NULL")
return None return None
try: try:
total, page = 0, 1 total, page, seen = 0, 1, 0
while True: while True:
data = _get_json( data = _get_json(
f"{LISTMONK_BASE}/api/subscribers?list_id={LISTMONK_LIST_ID}&per_page=100&page={page}", f"{LISTMONK_BASE}/api/subscribers?list_id={LISTMONK_LIST_ID}&per_page=100&page={page}",
@@ -107,10 +107,25 @@ def from_listmonk() -> int | None:
) or {} ) or {}
payload = data.get("data") or {} payload = data.get("data") or {}
rows = payload.get("results") or [] rows = payload.get("results") or []
total += sum(1 for s in rows if (s.get("status") or "") == "confirmed") # The subscriber's own `status` is enabled/blocked; the LIST
# membership status is what means "on this list" — counting the
# former returned a silent, wrong 0.
for s in rows:
for membership in s.get("lists") or []:
if membership.get("id") == LISTMONK_LIST_ID and (
membership.get("subscription_status") or ""
) == "confirmed":
total += 1
seen += len(rows)
if not rows or len(rows) < 100 or page >= 20: if not rows or len(rows) < 100 or page >= 20:
break break
page += 1 page += 1
if seen == 0:
# Nothing came back at all: the endpoint or payload shape changed.
# Record "not measured" (NULL) rather than a zero that reads as
# "nobody is subscribed".
print("metrics: listmonk returned no rows — newsletter_subs left NULL")
return None
return total return total
except Exception as exc: # noqa: BLE001 - report, never guess except Exception as exc: # noqa: BLE001 - report, never guess
print(f"metrics: listmonk read failed ({exc}) — newsletter_subs left NULL") print(f"metrics: listmonk read failed ({exc}) — newsletter_subs left NULL")