e1657f07d7
The homepage was flagging every park as weather delay because calendar.ts
collapsed "fetchLiveRides returned null" into the same openRides=0 bucket as
"all rides actually closed." Meanwhile every scraper (queuetimes, sixflags
operating-hours, sixflags wait-times) was swallowing non-OK responses and
exceptions silently, so logs gave no signal which upstream was failing or how.
Add a small scraperWarn helper that emits in the same shape as backend/log.ts
(without importing it — lib/scrapers is shared with the Next frontend). Use it
in all three scrapers to record HTTP status and error name+message before each
return null. Add parksSkipped to the tier-5 summary log so we can tell when the
openParks filter is rejecting everyone vs the fetcher silently failing.
Convert calendar.ts ridesCache to a discriminated union { kind: "ok" | "unknown" }.
Weather delay only fires on { kind: "ok", openRides: 0 }; unknown entries get
a 30s TTL so we recover quickly when upstream comes back and don't thunder-herd
in the meantime.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
23 lines
845 B
TypeScript
23 lines
845 B
TypeScript
/**
|
|
* Minimal structured warn-logger for scrapers. Matches the backend's
|
|
* `${ISO} [WARN] [tag] msg key=value...` shape so warns from these files
|
|
* grep alongside backend/src/log.ts output. Lives here (not in backend/)
|
|
* because lib/scrapers/ is imported by both backend and Next.js code —
|
|
* importing backend's log would cross a layering boundary.
|
|
*/
|
|
|
|
type Meta = Record<string, unknown>;
|
|
|
|
export function scraperWarn(tag: string, msg: string, meta?: Meta): void {
|
|
const parts: string[] = [];
|
|
if (meta) {
|
|
for (const [k, v] of Object.entries(meta)) {
|
|
if (v === undefined) continue;
|
|
const s = typeof v === "string" ? v : JSON.stringify(v);
|
|
parts.push(`${k}=${s}`);
|
|
}
|
|
}
|
|
const tail = parts.length ? " " + parts.join(" ") : "";
|
|
console.warn(`${new Date().toISOString()} [WARN] [${tag}] ${msg}${tail}`);
|
|
}
|