Make a never-attempted mirror visible, and stop replay restamping the date
Two real leads on 2026-08-26 landed in the DB with no Sheet row and no mirror
row at all: the empty-env window meant the Sheet call never ran. Because
/mirrors/failed looked for state='failed', a mirror that was never attempted
read exactly like one that was never owed, and the summary reported a clean
failed_mirrors: {} while two families were missing from the sheet.
/join now writes a `pending` mirror row for every target BEFORE attempting any
of them, so the gap between "owed" and "done" is a row rather than an absence.
set_mirror_pending never downgrades an attempted mirror. failed_mirror_records
covers failed and pending, since both need replaying, and summary reports
pending_mirrors alongside failed_mirrors.
sheet_append also stamped the Sheet with datetime.now(), so replaying a lead
filed it under the day of the replay rather than the day the family submitted.
It now takes the submission timestamp off the record and only falls back to now
when there isn't one.
This commit is contained in:
+11
-1
@@ -578,8 +578,12 @@ def sheet_append(rec):
|
||||
sheet.append_row(SHEET_HEADERS)
|
||||
elif len(vals[0]) == 7:
|
||||
sheet.update_cell(1, 8, "Comments")
|
||||
# The submission time, not the time of the write. A replay months later must
|
||||
# not relabel a lead as arriving today.
|
||||
stamp = (rec.get("ts") or "")[:16].replace("T", " ") \
|
||||
or datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
|
||||
sheet.append_row([
|
||||
datetime.datetime.now().strftime("%Y-%m-%d %H:%M"),
|
||||
stamp,
|
||||
rec["parent_name"], rec["email"], rec["phone"], rec["children"],
|
||||
rec["interested_in"], rec["source"], rec["message"],
|
||||
])
|
||||
@@ -653,6 +657,12 @@ def join_post(parent_name: str = Form(...), email: str = Form(...), phone: str =
|
||||
message=rec["message"], payload=rec, submitted_at=rec["ts"])
|
||||
except Exception as e:
|
||||
print("STORE WRITE FAILED for %s <%s>: %s" % (rec["parent_name"], rec["email"], e), flush=True)
|
||||
# Register every mirror as pending BEFORE attempting it. If the process dies
|
||||
# or a call never runs, the gap is visible and replayable instead of the row
|
||||
# simply having no mirror record at all.
|
||||
if record_id:
|
||||
for _t in store.TARGETS:
|
||||
store.set_mirror_pending(record_id, _t)
|
||||
sheet_error = None
|
||||
try:
|
||||
sheet_append(rec)
|
||||
|
||||
+32
-1
@@ -148,6 +148,28 @@ def insert_lead(parent_name, email, phone=None, interested_in=None, children=Non
|
||||
return rid
|
||||
|
||||
|
||||
def set_mirror_pending(record_id, target):
|
||||
"""Register a mirror as owed, before it is attempted.
|
||||
|
||||
Without this a mirror that never ran leaves no row at all, which reads
|
||||
identically to a mirror that was never owed. That is how two leads went
|
||||
missing from the Sheet on 2026-08-26 with a clean `failed_mirrors: {}`.
|
||||
Never downgrades an existing row - a mirror already ok or failed has been
|
||||
attempted, and its outcome stands.
|
||||
"""
|
||||
con = connect()
|
||||
try:
|
||||
con.execute(
|
||||
"INSERT INTO mirrors (record_id, target, state, attempts, last_attempt_at)"
|
||||
" VALUES (?,?,'pending',0,NULL)"
|
||||
" ON CONFLICT(record_id, target) DO NOTHING",
|
||||
(record_id, target),
|
||||
)
|
||||
con.commit()
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
|
||||
def set_mirror(record_id, target, ok, error=None):
|
||||
"""Record the outcome of an attempt to copy a row to an external target."""
|
||||
ts = _now()
|
||||
@@ -241,17 +263,26 @@ def summary():
|
||||
" ORDER BY c DESC")},
|
||||
"failed_mirrors": {r["target"]: r["c"] for r in con.execute(
|
||||
"SELECT target, COUNT(*) c FROM mirrors WHERE state='failed' GROUP BY target")},
|
||||
"pending_mirrors": {r["target"]: r["c"] for r in con.execute(
|
||||
"SELECT target, COUNT(*) c FROM mirrors WHERE state='pending' GROUP BY target")},
|
||||
}
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
|
||||
def failed_mirror_records(target, limit=50):
|
||||
"""Rows owing a copy to `target`: attempted and failed, or never attempted.
|
||||
|
||||
`pending` is included deliberately. A mirror that never ran needs replaying
|
||||
just as much as one that ran and failed, and it is the case that hid two
|
||||
leads on 2026-08-26.
|
||||
"""
|
||||
con = connect()
|
||||
try:
|
||||
return [_row(r) for r in con.execute(
|
||||
"SELECT l.* FROM join_leads l JOIN mirrors m ON m.record_id=l.id"
|
||||
" WHERE m.target=? AND m.state='failed' ORDER BY l.submitted_at LIMIT ?",
|
||||
" WHERE m.target=? AND m.state IN ('failed','pending')"
|
||||
" ORDER BY l.submitted_at LIMIT ?",
|
||||
(target, limit))]
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
Reference in New Issue
Block a user