From db682814ea5d984b87d841cdd8ad2a36cee32cad Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Sat, 10 Oct 2026 17:44:44 -0400 Subject: [PATCH] The rollup's last line names the traffic it counted, and the rollup and the backup check in once, when they end The closing summary still named the old parser's variables, so every run wrote its row and then died on the print, and Sentry was told the night failed. It reads the shared parser's counts now. The check-ins become one at the end with the run's duration: a start and a finish seconds apart can reach Sentry in either order, and a start that lands second is never closed. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GwFKMuQnPAEHJ5yA1q4orh --- deploy/waving-hands-backup.sh | 8 ++++++-- deploy/waving-hands-rollup.sh | 10 +++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/deploy/waving-hands-backup.sh b/deploy/waving-hands-backup.sh index fe9dbe4..8711cac 100755 --- a/deploy/waving-hands-backup.sh +++ b/deploy/waving-hands-backup.sh @@ -14,9 +14,14 @@ LOG="/var/log/waving-hands/backup.log" STAMP=$(date +%Y-%m-%d) mkdir -p "$(dirname "$LOG")" CRON_URL=$(cat /root/.waving-hands-sentry-cron 2>/dev/null || true) +# One check-in, when the run ends, carrying its duration: a start and a +# finish sent seconds apart can reach Sentry in either order, and a start +# that lands second is never closed. A run that never ends sends nothing, +# and Sentry marks the night missed. +START=$SECONDS checkin() { [ -n "$CRON_URL" ] && curl -sf -o /dev/null -X POST -H "Content-Type: application/json" \ - -d "{\"status\":\"$1\",\"monitor_config\":{\"schedule\":{\"type\":\"crontab\",\"value\":\"$SCHEDULE\"},\"checkin_margin\":30,\"max_runtime\":10,\"timezone\":\"UTC\"}}" \ + -d "{\"status\":\"$1\",\"duration\":$((SECONDS - START)),\"monitor_config\":{\"schedule\":{\"type\":\"crontab\",\"value\":\"$SCHEDULE\"},\"checkin_margin\":30,\"max_runtime\":10,\"timezone\":\"UTC\"}}" \ "$CRON_URL" || true } @@ -27,7 +32,6 @@ fi { echo "=== $(date -Is) backup start" - checkin in_progress if rclone sync "$SRC" "spaces:$BUCKET/$PREFIX/current" --exclude 'rollup.jsonl' 2>&1 && rclone copy "$SRC" "spaces:$BUCKET/$PREFIX/snapshots/$STAMP" 2>&1; then checkin ok diff --git a/deploy/waving-hands-rollup.sh b/deploy/waving-hands-rollup.sh index c035d57..977d440 100755 --- a/deploy/waving-hands-rollup.sh +++ b/deploy/waving-hands-rollup.sh @@ -16,13 +16,17 @@ DAY="${1:-$(date -u -d 'yesterday' +%Y-%m-%d)}" SCHEDULE="12 0 * * *" CRON_URL=$(cat /root/.waving-hands-sentry-cron-rollup 2>/dev/null || true) # The check-in carries the schedule: Sentry keeps a monitor only once told its shape. +# One check-in, when the run ends, carrying its duration: a start and a +# finish sent seconds apart can reach Sentry in either order, and a start +# that lands second is never closed. A run that never ends sends nothing, +# and Sentry marks the night missed. +START=$SECONDS checkin() { [ -n "$CRON_URL" ] && curl -sf -o /dev/null -X POST -H "Content-Type: application/json" \ - -d "{\"status\":\"$1\",\"monitor_config\":{\"schedule\":{\"type\":\"crontab\",\"value\":\"$SCHEDULE\"},\"checkin_margin\":30,\"max_runtime\":10,\"timezone\":\"UTC\"}}" \ + -d "{\"status\":\"$1\",\"duration\":$((SECONDS - START)),\"monitor_config\":{\"schedule\":{\"type\":\"crontab\",\"value\":\"$SCHEDULE\"},\"checkin_margin\":30,\"max_runtime\":10,\"timezone\":\"UTC\"}}" \ "$CRON_URL" || true } mkdir -p "$(dirname "$LOG")" -checkin in_progress if python3 - "$DAY" "$OUT" <<'PY' >> "$LOG" 2>&1 import collections, datetime, glob, gzip, json, os, re, shutil, sys day, out = sys.argv[1], sys.argv[2] @@ -72,6 +76,6 @@ rows.sort(key=lambda r: r["day"]) with open(out + ".tmp", "w") as fh: for r in rows: fh.write(json.dumps(r) + "\n") os.replace(out + ".tmp", out) -print("%s rolled: %d people, %d requests, %d rooms" % (day, len(hips), human, created)) +print("%s rolled: %d people, %d requests, %d rooms" % (day, len(t["addresses"]), t["human"], created)) PY then checkin ok; else checkin error; fi