← back to Beverlyhillsvideos
poster: harden for unattended ops (Cody terminal-gate FIX-FIRST)
49e3fa0cfb28e2fc8ced930e7a6b10fc5580a647 · 2026-08-07 06:50:16 -0700 · Steve Abrams
- reachable(): 5s AbortController timeout so a hung video server can't freeze a slot.
- watchdog: detect SILENT missed slots (post.log stale >8h = cadence stopped, no
error line to catch it otherwise) + write data/latest.json heartbeat for the
meta-watchdog; bumped daily→4x/day (2/8/14/20, offset 2h after each post slot).
Files touched
M social/poster/post-daily.mjsM social/poster/token-health-run.sh
Diff
commit 49e3fa0cfb28e2fc8ced930e7a6b10fc5580a647
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Fri Aug 7 06:50:16 2026 -0700
poster: harden for unattended ops (Cody terminal-gate FIX-FIRST)
- reachable(): 5s AbortController timeout so a hung video server can't freeze a slot.
- watchdog: detect SILENT missed slots (post.log stale >8h = cadence stopped, no
error line to catch it otherwise) + write data/latest.json heartbeat for the
meta-watchdog; bumped daily→4x/day (2/8/14/20, offset 2h after each post slot).
---
social/poster/post-daily.mjs | 7 ++++++-
social/poster/token-health-run.sh | 35 ++++++++++++++++++++++++++++++-----
2 files changed, 36 insertions(+), 6 deletions(-)
diff --git a/social/poster/post-daily.mjs b/social/poster/post-daily.mjs
index 7b9f475..9b8309d 100644
--- a/social/poster/post-daily.mjs
+++ b/social/poster/post-daily.mjs
@@ -54,11 +54,16 @@ const verticalUrl = (film) =>
: `${cfg.siteBase}${film.src.replace('/video/', '/video/vertical/')}`;
async function reachable(url) {
+ // 5s abort so a hung (non-refusing) server can't freeze the whole posting slot.
+ const ac = new AbortController();
+ const t = setTimeout(() => ac.abort(), 5000);
try {
- const res = await fetch(url, { method: 'HEAD' });
+ const res = await fetch(url, { method: 'HEAD', signal: ac.signal });
return res.ok && (res.headers.get('content-type') || '').includes('video');
} catch {
return false;
+ } finally {
+ clearTimeout(t);
}
}
diff --git a/social/poster/token-health-run.sh b/social/poster/token-health-run.sh
index ab113bc..c16f07b 100755
--- a/social/poster/token-health-run.sh
+++ b/social/poster/token-health-run.sh
@@ -1,11 +1,36 @@
#!/bin/zsh
-# Daily BHV posting watchdog: token health + recent post failures. Alerts via CNCP on trouble.
+# BHV posting watchdog: (1) token health, (2) recent live-post failures, (3) SILENT
+# missed-slot detection — if the 6h cadence stopped firing (Mac2 asleep/launchd dead),
+# no error line is ever written, so we detect it by post.log going stale. Alerts via CNCP.
+# Writes data/latest.json each run as a heartbeat the dw-canary-meta-watchdog can watch.
cd "$(dirname "$0")/../.." || exit 1
+LOG=social/poster/post.log
+mkdir -p social/poster/data
+
OUT=$(/opt/homebrew/bin/node social/poster/token-health.mjs 2>&1); RC=$?
-# also flag if the last few post.log runs recorded a live POST FAILED
-FAILS=$(tail -40 social/poster/post.log 2>/dev/null | grep -c "POST FAILED")
-if [[ $RC -ne 0 || $FAILS -gt 0 ]]; then
- MSG="BHV Instagram watchdog: token=[$OUT] recentPostFailures=$FAILS"
+FAILS=$(tail -60 "$LOG" 2>/dev/null | grep -c "POST FAILED")
+
+# Age (hours) of the newest scheduled run header ("----- <ts> · slot=... -----").
+STALE_H=$(/opt/homebrew/bin/node -e '
+try{
+ const fs=require("fs");
+ const lines=fs.readFileSync("social/poster/post.log","utf8").trim().split("\n").filter(l=>l.startsWith("----- "));
+ if(!lines.length){console.log(999);process.exit(0);}
+ const m=lines[lines.length-1].match(/----- (.+?) (?:PDT|PST|[A-Z]{2,4}) ·/);
+ const t=m?Date.parse(m[1].replace(" ","T")):NaN;
+ console.log(isNaN(t)?999:((Date.now()-t)/3.6e6).toFixed(1));
+}catch{console.log(999);}
+' 2>/dev/null)
+# 6h cadence + grace: >8h since the last run means a slot was silently missed.
+MISSED=$(/opt/homebrew/bin/node -e "console.log(parseFloat('${STALE_H:-999}')>8?1:0)" 2>/dev/null)
+
+STATE="HEALTHY"
+if [[ $RC -ne 0 || $FAILS -gt 0 || $MISSED -eq 1 ]]; then STATE="ALERT"; fi
+printf '{"ts":"%s","state":"%s","recentFailures":%s,"hoursSinceLastRun":%s}\n' \
+ "$(date -u +%FT%TZ)" "$STATE" "${FAILS:-0}" "${STALE_H:-999}" > social/poster/data/latest.json
+
+if [[ "$STATE" == "ALERT" ]]; then
+ MSG="BHV IG watchdog: token=[$OUT] recentFailures=$FAILS hoursSinceLastPost=${STALE_H} missedSlot=$MISSED"
curl -s -X POST http://127.0.0.1:3333/api/parking-lot -H 'Content-Type: application/json' \
-d "{\"project\":\"beverlyhillsvideos\",\"title\":\"BHV posting needs attention\",\"note\":\"$MSG\"}" >/dev/null 2>&1 || true
echo "$(date) ALERT: $MSG" >> social/poster/watchdog.log
← c461668 BHV watcher: fail-loud (heartbeat latest.json + CNCP alert o
·
back to Beverlyhillsvideos
·
auto-data-snapshot: 2026-08-07T06:58:19 (2 data files) — soc afa1634 →