Session 7b: Fix pipeline - body parser, Redis queueing, poller visibility, auto-start

This commit is contained in:
Kev
2026-06-10 01:22:55 -04:00
parent b0890dadae
commit 5c44922937
11 changed files with 322 additions and 27 deletions
+31 -2
View File
@@ -234,6 +234,20 @@ async function tick(sportCfg) {
console.warn(`[poller-${SPORT}] scoreboard fetch failed: ${err.message}`);
return;
}
// Bucket games by status so every tick surfaces what we're observing —
// without this, an NBA Finals night with one game stuck in 'pre' looks
// identical to a silent crash. Visibility > debugging in the dark.
const bucket = { pre: 0, in: 0, post: 0, other: 0 };
for (const g of games) {
const s = (g.state || 'other').toLowerCase();
if (bucket[s] !== undefined) bucket[s] += 1;
else bucket.other += 1;
}
console.log(
`[poller-${SPORT}] tick — ${games.length} games (pre=${bucket.pre} in=${bucket.in} post=${bucket.post}${bucket.other ? ` other=${bucket.other}` : ''})`
);
for (const g of games) {
try { await handleGame(g, sportCfg); }
catch (err) { console.warn(`[poller-${SPORT}] game ${g.id} handler error: ${err.message}`); }
@@ -254,15 +268,30 @@ async function main() {
console.log(`[poller-${SPORT}] starting — pollInterval=${POLL_INTERVAL_MS}ms buffer=${BUFFER_MS}ms`);
// Run forever. The PM2 supervisor restarts on crash; tick errors are
// already caught inside.
// already caught inside. Wrap the cycle in try/catch so a missed
// rejection inside tick() doesn't silently kill the loop.
/* eslint-disable no-constant-condition */
while (true) {
await tick(sportCfg);
try {
await tick(sportCfg);
} catch (err) {
console.error(`[poller-${SPORT}] tick error:`, err?.stack || err?.message || err);
}
const intervalMs = inGameHours(sportCfg) ? POLL_INTERVAL_MS : OFF_HOURS_POLL_MS;
await new Promise((r) => setTimeout(r, intervalMs));
}
}
// Surface unhandled rejections / uncaught exceptions in PM2 logs. Without
// these handlers the process can die silently with no stderr — which is
// the symptom 7b is asked to fix.
process.on('unhandledRejection', (reason) => {
console.error(`[poller-${SPORT}] unhandledRejection:`, reason?.stack || reason);
});
process.on('uncaughtException', (err) => {
console.error(`[poller-${SPORT}] uncaughtException:`, err?.stack || err?.message || err);
});
// Surface for tests — they import individual handlers without firing main().
module.exports = {
isFinalStatus,